<!DOCTYPE html>
<html>

<head>
	<meta charset="utf-8">
	<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
	<meta name="theme-color" content="#33474d">
	<title>失落的乐章</title>
	<link rel="stylesheet" href="/css/style.css" />
	
      <link rel="alternate" href="/atom.xml" title="失落的乐章" type="application/atom+xml">
    
</head>

<body>

	<header class="header">
		<nav class="header__nav">
			
				<a href="/archives" class="header__link">Archive</a>
			
				<a href="/tags" class="header__link">Tags</a>
			
				<a href="/atom.xml" class="header__link">RSS</a>
			
		</nav>
		<h1 class="header__title"><a href="/">失落的乐章</a></h1>
		<h2 class="header__subtitle">技术面前，永远都是学生。</h2>
	</header>

	<main>
		
	<span class="different-posts different-posts_earlier">📖 <a href="/page/26">earlier posts</a> 📖</span>




	<article>
	
		<h1><a href="/2017/10/12/MySQL/9. mysql的root密码重置/">mysql的root密码重置</a></h1>
	
	<div class="article__infos">
		<span class="article__date">2017-10-12</span><br />
		
		
			<span class="article__tags">
			  	<a class="article__tag-link" href="/tags/MySQL/">MySQL</a>
			</span>
		
	</div>

	

	
		<h2 id="mysql设置密码"><a href="#mysql设置密码" class="headerlink" title="mysql设置密码"></a>mysql设置密码</h2><figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">[root@lamp ~]<span class="comment"># mysqladmin -uroot password 'yanyi'</span></div></pre></td></tr></table></figure>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;注意：如果mysql已经有密码，该命令要加上 -p</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">[root@lamp ~]<span class="comment"># mysqladmin -uroot -pyanyi password '123456'</span></div></pre></td></tr></table></figure>
<h2 id="碰到mysql-root密码忘记该如何做呢？"><a href="#碰到mysql-root密码忘记该如何做呢？" class="headerlink" title="碰到mysql root密码忘记该如何做呢？"></a>碰到mysql root密码忘记该如何做呢？</h2><h3 id="1-编辑mysql主配置文件my-cnf"><a href="#1-编辑mysql主配置文件my-cnf" class="headerlink" title="1.编辑mysql主配置文件my.cnf"></a>1.编辑mysql主配置文件my.cnf</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">[root@lamp ~]<span class="comment"># vim /etc/my.cnf</span></div></pre></td></tr></table></figure>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;在 [mysql] 字段下添加参数</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">skip-grant</div></pre></td></tr></table></figure>
<h3 id="2-重启数据库服务"><a href="#2-重启数据库服务" class="headerlink" title="2.重启数据库服务"></a>2.重启数据库服务</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">[root@lamp ~]<span class="comment"># service mysqld restart</span></div></pre></td></tr></table></figure>
<h3 id="3-进入mysql数据库（此时数据库不用授权）"><a href="#3-进入mysql数据库（此时数据库不用授权）" class="headerlink" title="3.进入mysql数据库（此时数据库不用授权）"></a>3.进入mysql数据库（此时数据库不用授权）</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">[root@lamp ~]<span class="comment"># /usr/local/mysql/bin/mysql -uroot</span></div></pre></td></tr></table></figure>
<h3 id="4-修改相应的用户密码"><a href="#4-修改相应的用户密码" class="headerlink" title="4.修改相应的用户密码"></a>4.修改相应的用户密码</h3><p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;使用mysql库</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">mysql&gt; use mysql;</div></pre></td></tr></table></figure>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;更新一个表</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div></pre></td><td class="code"><pre><div class="line">mysql&gt; update user <span class="built_in">set</span> password=password(<span class="string">'yanyi'</span>) <span class="built_in">where</span> user=<span class="string">'root'</span>;</div><div class="line">mysql&gt; select * from user <span class="built_in">where</span> user=<span class="string">'root'</span>\G;</div><div class="line">mysql&gt; flush privileges;</div><div class="line">mysql&gt; quit;</div></pre></td></tr></table></figure>
<h3 id="5-修改-etc-my-cnf去掉skip-grant，重启mysql服务"><a href="#5-修改-etc-my-cnf去掉skip-grant，重启mysql服务" class="headerlink" title="5.修改/etc/my.cnf去掉skip-grant，重启mysql服务"></a>5.修改/etc/my.cnf去掉skip-grant，重启mysql服务</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div></pre></td><td class="code"><pre><div class="line">[root@lamp ~]<span class="comment"># vim /etc/my.cnf</span></div><div class="line">[root@lamp ~]<span class="comment"># service mysqld restart</span></div></pre></td></tr></table></figure>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;这样就可以用新密码登录了</p>
<p><figure class="figure"><img src="https://github.com/hcldirgit/image/blob/master/mysql%E7%9A%84root%E5%AF%86%E7%A0%81%E9%87%8D%E7%BD%AE/01.png?raw=true" alt=""></figure></p>

	

	

</article>




	<article>
	
		<h1><a href="/2017/10/12/MySQL/8. 关于mysql一些优化心得/">关于mysql一些优化心得</a></h1>
	
	<div class="article__infos">
		<span class="article__date">2017-10-12</span><br />
		
		
			<span class="article__tags">
			  	<a class="article__tag-link" href="/tags/MySQL/">MySQL</a>
			</span>
		
	</div>

	

	
		<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;<strong>先介绍下服务器架构及配置8核8G，10M带宽Centos6.5 64</strong></p>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;<strong>Nginx&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;1.8.1PHP   &#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;5.3.29Mysql&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;5.5.42</strong></p>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;一电商网站后台查询订单时 经常php超时，导致php报错以下是排查过程</p>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;一、php执行超时，首先我们想到的就是php.ini文件中max_execution_time =  #把默认的值调整了下</p>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;二、然后在后台执行订单查询php不报错了，但是查询耗时较长，用时65s.  而且一些表成锁死状态碎片比较多，本人对mysql数据库优化不是很了解，于是百度了一下：一般mysql调优主要是根据慢查询日志去优化sql语句，my.cnf里面没啥可调的。 下面就是分析mysql慢日志,调整参数3、mysql参数优化，主要调整的参数如下。根据机器性能来调整，如果你对参数不是很了解，建议不要盲目的调</p>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;把一些配置文件修改好后重启相关服务，由原来的65s变成了十几秒。效果还是不是很理想，查看了下mysql默认引擎为MyISAM，决定把引擎改为Innodb</p>
<ol>
<li>导出shop数据库的表结构</li>
</ol>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">mysqldump -d -uxxx -p shop &gt; shop_table.sql</div></pre></td></tr></table></figure>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;其中-d参数表示不导出数据，只导出表结构</p>
<ol>
<li>替换shop_table.sql里的MyISAM为INNODB</li>
</ol>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">sed -i <span class="string">'s/MyISAM/INNODB/g'</span> shop_table.sql</div></pre></td></tr></table></figure>
<ol>
<li>新建数据库shop_new,并导入表结构</li>
</ol>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">mysql &gt; create database shop_new;mysql -uroot -p shop_new &lt; shop_table.sql</div></pre></td></tr></table></figure>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;可以通过show table status来检查表引擎是否为INNODB。</p>
<ol>
<li>导出shop的数据</li>
</ol>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">mysqldump -t -uroot -p shop &gt; shop_data.sql</div></pre></td></tr></table></figure>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;其中-t参数表示只导数据，不导表结构</p>
<ol>
<li>导入数据到</li>
</ol>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">shop_newmysql -uroot -p shop_new &lt; shop_data.sql</div></pre></td></tr></table></figure>
<ol>
<li>首先开启慢日志，修改/etc/my.cnf  增加以下两段配置，保存重启mysql</li>
</ol>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div></pre></td><td class="code"><pre><div class="line">vim /etc/my.cnf</div><div class="line"></div><div class="line">long_query_time = 2</div><div class="line">log_slow_queries = /data/mysql/slow.log</div></pre></td></tr></table></figure>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;重启mysql服务</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">service mysqld restart</div></pre></td></tr></table></figure>
<ol>
<li>查看慢日志来定位mysql哪条语句执行慢，然后建立索引，优化sql执行语句。</li>
</ol>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div></pre></td><td class="code"><pre><div class="line">&lt;font color=<span class="string">"Red"</span>&gt;tail -n20 /data/mysql/slow.log <span class="comment">#查看20行&lt;/font&gt;</span></div><div class="line"> </div><div class="line"> </div><div class="line"> <span class="comment"># Time: 160303 12:12:38</span></div><div class="line"> <span class="comment"># User@Host: root[root] @ [10.165.34.182]</span></div><div class="line"> <span class="comment"># Query_time: 10.145685 Lock_time: 0.000395 Rows_sent: 1 Rows_examined: 24306970</span></div><div class="line"> use shop;</div><div class="line">SET timestamp=1456978358;</div><div class="line"> SELECT COUNT(*) FROM `shop`.`ecs_order_info` o LEFT JOIN`shop`.`ecs_users` u ON o.user_id = u.user_id LEFT JOIN `shop`.`ecs_affiliate_log` a ON o.order_id = a.order_id WHERE o.user_id &gt; 0 AND (u.parent_id &gt; 0 AND o.is_separate = 0 OR o.is_separate &gt; 0);</div><div class="line"> <span class="comment"># Time: 160303 12:12:44</span></div><div class="line"> <span class="comment"># User@Host: root[root] @ [10.165.34.182]</span></div><div class="line"> <span class="comment"># Query_time: 6.073441 Lock_time: 0.000152 Rows_sent: 15 Rows_examined: 24314767</span></div><div class="line">SET timestamp=1456978364;</div><div class="line">SELECT o.*, a.log_id, a.user_id as suid, a.user_name as auser, a.money, a.point, a.separate_type,u.parent_id as up FROM `shop`.`ecs_order_info` o LEFT JOIN`shop`.`ecs_users` u ON o.user_id = u.user_id LEFT JOIN `shop`.`ecs_affiliate_log` a ON o.order_id = a.order_id WHERE o.user_id &gt; 0 AND (u.parent_id &gt; 0 AND o.is_separate = 0 OR o.is_separate &gt; 0) ORDER BY order_id DESC LIMIT 0,15;</div></pre></td></tr></table></figure>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;通过慢日志发现其中有几个表查询耗时较长，下面就是把这个查询慢的表建立索引</p>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;用到的软件 NAvicat，对查询慢的表进行设计，增加索引</p>
<p><figure class="figure"><img src="https://github.com/hcldirgit/image/blob/master/%E5%85%B3%E4%BA%8Emysql%E4%B8%80%E4%BA%9B%E4%BC%98%E5%8C%96%E5%BF%83%E5%BE%97/01.png?raw=true" alt=""></figure></p>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;根据 explain 的解释，查看下索引是否建立，一般都是这样调整就行。</p>
<p><figure class="figure"><img src="https://github.com/hcldirgit/image/blob/master/%E5%85%B3%E4%BA%8Emysql%E4%B8%80%E4%BA%9B%E4%BC%98%E5%8C%96%E5%BF%83%E5%BE%97/02.png?raw=true" alt=""></figure></p>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;修改完后重启 mysql 服务，查询时间从65s,缩短到 0.017407 秒</p>
<p><figure class="figure"><img src="https://github.com/hcldirgit/image/blob/master/%E5%85%B3%E4%BA%8Emysql%E4%B8%80%E4%BA%9B%E4%BC%98%E5%8C%96%E5%BF%83%E5%BE%97/03.png?raw=true" alt=""></figure></p>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;参考了大量的网络资料，头一次搞优化。优化完后很有成就感，算是一次新的挑战</p>

	

	

</article>




	<article>
	
		<h1><a href="/2017/10/12/MySQL/7. MySQL性能调优my.cnf详解/">MySQL性能调优my.cnf详解</a></h1>
	
	<div class="article__infos">
		<span class="article__date">2017-10-12</span><br />
		
		
			<span class="article__tags">
			  	<a class="article__tag-link" href="/tags/MySQL/">MySQL</a>
			</span>
		
	</div>

	

	
		<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;提供一个MySQL 5.6版本适合在1GB内存VPS上的my.cnf配置文件</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div><div class="line">28</div><div class="line">29</div><div class="line">30</div><div class="line">31</div><div class="line">32</div><div class="line">33</div><div class="line">34</div><div class="line">35</div><div class="line">36</div><div class="line">37</div><div class="line">38</div><div class="line">39</div><div class="line">40</div><div class="line">41</div><div class="line">42</div><div class="line">43</div><div class="line">44</div><div class="line">45</div><div class="line">46</div><div class="line">47</div><div class="line">48</div><div class="line">49</div><div class="line">50</div><div class="line">51</div><div class="line">52</div><div class="line">53</div><div class="line">54</div><div class="line">55</div><div class="line">56</div><div class="line">57</div><div class="line">58</div><div class="line">59</div><div class="line">60</div><div class="line">61</div><div class="line">62</div><div class="line">63</div><div class="line">64</div><div class="line">65</div><div class="line">66</div><div class="line">67</div><div class="line">68</div><div class="line">69</div><div class="line">70</div><div class="line">71</div><div class="line">72</div><div class="line">73</div><div class="line">74</div><div class="line">75</div><div class="line">76</div><div class="line">77</div><div class="line">78</div><div class="line">79</div><div class="line">80</div><div class="line">81</div><div class="line">82</div><div class="line">83</div><div class="line">84</div><div class="line">85</div><div class="line">86</div><div class="line">87</div><div class="line">88</div><div class="line">89</div><div class="line">90</div></pre></td><td class="code"><pre><div class="line">[client]</div><div class="line">port = 3306</div><div class="line">socket = /tmp/mysql.sock</div><div class="line"></div><div class="line">[mysqld]</div><div class="line">port = 3306</div><div class="line">socket = /tmp/mysql.sock</div><div class="line"></div><div class="line">basedir = /usr/<span class="built_in">local</span>/mysql</div><div class="line">datadir = /data/mysql</div><div class="line">pid-file = /data/mysql/mysql.pid</div><div class="line">user = mysql</div><div class="line"><span class="built_in">bind</span>-address = 0.0.0.0</div><div class="line">server-id = 1</div><div class="line"></div><div class="line">skip-name-resolve</div><div class="line"><span class="comment">#skip-networking</span></div><div class="line">back_log = 600</div><div class="line"></div><div class="line">max_connections = 1000</div><div class="line">max_connect_errors = 6000</div><div class="line">open_files_limit = 65535</div><div class="line">table_open_cache = 128 </div><div class="line">max_allowed_packet = 4M</div><div class="line">binlog_cache_size = 1M</div><div class="line">max_heap_table_size = 8M</div><div class="line">tmp_table_size = 16M</div><div class="line"></div><div class="line">read_buffer_size = 2M</div><div class="line">read_rnd_buffer_size = 8M</div><div class="line">sort_buffer_size = 8M</div><div class="line">join_buffer_size = 8M</div><div class="line">key_buffer_size = 4M</div><div class="line"></div><div class="line">thread_cache_size = 8</div><div class="line"></div><div class="line">query_cache_size = 8M</div><div class="line">query_cache_limit = 2M</div><div class="line"></div><div class="line">ft_min_word_len = 4</div><div class="line"></div><div class="line">log_bin = mysql-bin</div><div class="line">binlog_format = mixed</div><div class="line">expire_logs_days = 30</div><div class="line"></div><div class="line">log_error = /data/mysql/mysql-error.log</div><div class="line">slow_query_log = 1</div><div class="line">long_query_time = 1</div><div class="line">slow_query_log_file = /data/mysql/mysql-slow.log</div><div class="line"></div><div class="line">performance_schema = 0</div><div class="line">explicit_defaults_for_timestamp</div><div class="line"></div><div class="line"><span class="comment">#lower_case_table_names = 1</span></div><div class="line"></div><div class="line">skip-external-locking</div><div class="line"></div><div class="line">default_storage_engine = InnoDB</div><div class="line"><span class="comment">#default-storage-engine = MyISAM</span></div><div class="line">innodb_file_per_table = 1</div><div class="line">innodb_open_files = 500</div><div class="line">innodb_buffer_pool_size = 64M</div><div class="line">innodb_write_io_threads = 4</div><div class="line">innodb_read_io_threads = 4</div><div class="line">innodb_thread_concurrency = 0</div><div class="line">innodb_purge_threads = 1</div><div class="line">innodb_flush_log_at_trx_commit = 2</div><div class="line">innodb_log_buffer_size = 2M</div><div class="line">innodb_log_file_size = 32M</div><div class="line">innodb_log_files_in_group = 3</div><div class="line">innodb_max_dirty_pages_pct = 90</div><div class="line">innodb_lock_wait_timeout = 120</div><div class="line"></div><div class="line">bulk_insert_buffer_size = 8M</div><div class="line">myisam_sort_buffer_size = 8M</div><div class="line">myisam_max_sort_file_size = 10G</div><div class="line">myisam_repair_threads = 1</div><div class="line"></div><div class="line">interactive_timeout = 28800</div><div class="line">wait_timeout = 28800</div><div class="line"></div><div class="line">[mysqldump]</div><div class="line">quick</div><div class="line">max_allowed_packet = 16M</div><div class="line"></div><div class="line">[myisamchk]</div><div class="line">key_buffer_size = 8M</div><div class="line">sort_buffer_size = 8M</div><div class="line">read_buffer = 4M</div><div class="line">write_buffer = 4M</div></pre></td></tr></table></figure>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;详细说明</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div><div class="line">28</div><div class="line">29</div><div class="line">30</div><div class="line">31</div><div class="line">32</div><div class="line">33</div><div class="line">34</div><div class="line">35</div><div class="line">36</div><div class="line">37</div><div class="line">38</div><div class="line">39</div><div class="line">40</div><div class="line">41</div><div class="line">42</div><div class="line">43</div><div class="line">44</div><div class="line">45</div><div class="line">46</div><div class="line">47</div><div class="line">48</div><div class="line">49</div><div class="line">50</div><div class="line">51</div><div class="line">52</div><div class="line">53</div><div class="line">54</div><div class="line">55</div><div class="line">56</div><div class="line">57</div><div class="line">58</div><div class="line">59</div><div class="line">60</div><div class="line">61</div><div class="line">62</div><div class="line">63</div><div class="line">64</div><div class="line">65</div><div class="line">66</div><div class="line">67</div><div class="line">68</div><div class="line">69</div><div class="line">70</div><div class="line">71</div><div class="line">72</div><div class="line">73</div><div class="line">74</div><div class="line">75</div><div class="line">76</div><div class="line">77</div><div class="line">78</div><div class="line">79</div><div class="line">80</div><div class="line">81</div><div class="line">82</div><div class="line">83</div><div class="line">84</div><div class="line">85</div><div class="line">86</div><div class="line">87</div><div class="line">88</div><div class="line">89</div><div class="line">90</div><div class="line">91</div><div class="line">92</div><div class="line">93</div><div class="line">94</div><div class="line">95</div><div class="line">96</div><div class="line">97</div><div class="line">98</div><div class="line">99</div><div class="line">100</div><div class="line">101</div><div class="line">102</div><div class="line">103</div><div class="line">104</div><div class="line">105</div><div class="line">106</div><div class="line">107</div><div class="line">108</div><div class="line">109</div><div class="line">110</div><div class="line">111</div><div class="line">112</div><div class="line">113</div><div class="line">114</div><div class="line">115</div><div class="line">116</div><div class="line">117</div><div class="line">118</div><div class="line">119</div><div class="line">120</div><div class="line">121</div><div class="line">122</div><div class="line">123</div><div class="line">124</div><div class="line">125</div><div class="line">126</div><div class="line">127</div><div class="line">128</div><div class="line">129</div><div class="line">130</div><div class="line">131</div><div class="line">132</div><div class="line">133</div><div class="line">134</div><div class="line">135</div><div class="line">136</div><div class="line">137</div><div class="line">138</div><div class="line">139</div><div class="line">140</div><div class="line">141</div><div class="line">142</div><div class="line">143</div><div class="line">144</div><div class="line">145</div><div class="line">146</div><div class="line">147</div><div class="line">148</div><div class="line">149</div><div class="line">150</div><div class="line">151</div><div class="line">152</div><div class="line">153</div><div class="line">154</div><div class="line">155</div><div class="line">156</div><div class="line">157</div><div class="line">158</div><div class="line">159</div><div class="line">160</div><div class="line">161</div><div class="line">162</div><div class="line">163</div><div class="line">164</div><div class="line">165</div><div class="line">166</div><div class="line">167</div><div class="line">168</div><div class="line">169</div><div class="line">170</div><div class="line">171</div><div class="line">172</div><div class="line">173</div><div class="line">174</div><div class="line">175</div><div class="line">176</div><div class="line">177</div><div class="line">178</div><div class="line">179</div><div class="line">180</div><div class="line">181</div><div class="line">182</div><div class="line">183</div><div class="line">184</div><div class="line">185</div><div class="line">186</div><div class="line">187</div><div class="line">188</div><div class="line">189</div><div class="line">190</div><div class="line">191</div><div class="line">192</div><div class="line">193</div><div class="line">194</div><div class="line">195</div><div class="line">196</div><div class="line">197</div><div class="line">198</div><div class="line">199</div><div class="line">200</div><div class="line">201</div><div class="line">202</div><div class="line">203</div><div class="line">204</div><div class="line">205</div><div class="line">206</div><div class="line">207</div><div class="line">208</div><div class="line">209</div><div class="line">210</div><div class="line">211</div><div class="line">212</div><div class="line">213</div><div class="line">214</div><div class="line">215</div><div class="line">216</div><div class="line">217</div><div class="line">218</div><div class="line">219</div><div class="line">220</div><div class="line">221</div></pre></td><td class="code"><pre><div class="line">[client] </div><div class="line">port = 3306 </div><div class="line">socket = /tmp/mysql.sock </div><div class="line"></div><div class="line">[mysqld] </div><div class="line">port = 3306 </div><div class="line">socket = /tmp/mysql.sock </div><div class="line"></div><div class="line">basedir = /usr/<span class="built_in">local</span>/mysql </div><div class="line">datadir = /data/mysql </div><div class="line">pid-file = /data/mysql/mysql.pid </div><div class="line">user = mysql </div><div class="line"><span class="built_in">bind</span>-address = 0.0.0.0 </div><div class="line">server-id = 1 <span class="comment">#表示是本机的序号为1,一般来讲就是master的意思 </span></div><div class="line"></div><div class="line">skip-name-resolve </div><div class="line"><span class="comment"># 禁止MySQL对外部连接进行DNS解析，使用这一选项可以消除MySQL进行DNS解析的时间。但需要注意，如果开启该选项， </span></div><div class="line"><span class="comment"># 则所有远程主机连接授权都要使用IP地址方式，否则MySQL将无法正常处理连接请求 </span></div><div class="line"></div><div class="line"><span class="comment">#skip-networking </span></div><div class="line"></div><div class="line">back_log = 600 </div><div class="line"><span class="comment"># MySQL能有的连接数量。当主要MySQL线程在一个很短时间内得到非常多的连接请求，这就起作用， </span></div><div class="line"><span class="comment"># 然后主线程花些时间(尽管很短)检查连接并且启动一个新线程。back_log值指出在MySQL暂时停止回答新请求之前的短时间内多少个请求可以被存在堆栈中。 </span></div><div class="line"><span class="comment"># 如果期望在一个短时间内有很多连接，你需要增加它。也就是说，如果MySQL的连接数据达到max_connections时，新来的请求将会被存在堆栈中， </span></div><div class="line"><span class="comment"># 以等待某一连接释放资源，该堆栈的数量即back_log，如果等待连接的数量超过back_log，将不被授予连接资源。 </span></div><div class="line"><span class="comment"># 另外，这值（back_log）限于您的操作系统对到来的TCP/IP连接的侦听队列的大小。 </span></div><div class="line"><span class="comment"># 你的操作系统在这个队列大小上有它自己的限制（可以检查你的OS文档找出这个变量的最大值），试图设定back_log高于你的操作系统的限制将是无效的。 </span></div><div class="line"></div><div class="line">max_connections = 1000 </div><div class="line"><span class="comment"># MySQL的最大连接数，如果服务器的并发连接请求量比较大，建议调高此值，以增加并行连接数量，当然这建立在机器能支撑的情况下，因为如果连接数越多，介于MySQL会为每个连接提供连接缓冲区，就会开销越多的内存，所以要适当调整该值，不能盲目提高设值。可以过'conn%'通配符查看当前状态的连接数量，以定夺该值的大小。 </span></div><div class="line"></div><div class="line">max_connect_errors = 6000 </div><div class="line"><span class="comment"># 对于同一主机，如果有超出该参数值个数的中断错误连接，则该主机将被禁止连接。如需对该主机进行解禁，执行：FLUSH HOST。 </span></div><div class="line"></div><div class="line">open_files_limit = 65535 </div><div class="line"><span class="comment"># MySQL打开的文件描述符限制，默认最小1024;当open_files_limit没有被配置的时候，比较max_connections*5和ulimit -n的值，哪个大用哪个， </span></div><div class="line"><span class="comment"># 当open_file_limit被配置的时候，比较open_files_limit和max_connections*5的值，哪个大用哪个。 </span></div><div class="line"></div><div class="line">table_open_cache = 128 </div><div class="line"><span class="comment"># MySQL每打开一个表，都会读入一些数据到table_open_cache缓存中，当MySQL在这个缓存中找不到相应信息时，才会去磁盘上读取。默认值64 </span></div><div class="line"><span class="comment"># 假定系统有200个并发连接，则需将此参数设置为200*N(N为每个连接所需的文件描述符数目)； </span></div><div class="line"><span class="comment"># 当把table_open_cache设置为很大时，如果系统处理不了那么多文件描述符，那么就会出现客户端失效，连接不上 </span></div><div class="line"></div><div class="line">max_allowed_packet = 4M </div><div class="line"><span class="comment"># 接受的数据包大小；增加该变量的值十分安全，这是因为仅当需要时才会分配额外内存。例如，仅当你发出长查询或MySQLd必须返回大的结果行时MySQLd才会分配更多内存。 </span></div><div class="line"><span class="comment"># 该变量之所以取较小默认值是一种预防措施，以捕获客户端和服务器之间的错误信息包，并确保不会因偶然使用大的信息包而导致内存溢出。 </span></div><div class="line"></div><div class="line">binlog_cache_size = 1M </div><div class="line"><span class="comment"># 一个事务，在没有提交的时候，产生的日志，记录到Cache中；等到事务提交需要提交的时候，则把日志持久化到磁盘。默认binlog_cache_size大小32K </span></div><div class="line"></div><div class="line">max_heap_table_size = 8M </div><div class="line"><span class="comment"># 定义了用户可以创建的内存表(memory table)的大小。这个值用来计算内存表的最大行数值。这个变量支持动态改变 </span></div><div class="line"></div><div class="line">tmp_table_size = 16M </div><div class="line"><span class="comment"># MySQL的heap（堆积）表缓冲大小。所有联合在一个DML指令内完成，并且大多数联合甚至可以不用临时表即可以完成。 </span></div><div class="line"><span class="comment"># 大多数临时表是基于内存的(HEAP)表。具有大的记录长度的临时表 (所有列的长度的和)或包含BLOB列的表存储在硬盘上。 </span></div><div class="line"><span class="comment"># 如果某个内部heap（堆积）表大小超过tmp_table_size，MySQL可以根据需要自动将内存中的heap表改为基于硬盘的MyISAM表。还可以通过设置tmp_table_size选项来增加临时表的大小。也就是说，如果调高该值，MySQL同时将增加heap表的大小，可达到提高联接查询速度的效果 </span></div><div class="line"></div><div class="line">read_buffer_size = 2M </div><div class="line"><span class="comment"># MySQL读入缓冲区大小。对表进行顺序扫描的请求将分配一个读入缓冲区，MySQL会为它分配一段内存缓冲区。read_buffer_size变量控制这一缓冲区的大小。 </span></div><div class="line"><span class="comment"># 如果对表的顺序扫描请求非常频繁，并且你认为频繁扫描进行得太慢，可以通过增加该变量值以及内存缓冲区大小提高其性能 </span></div><div class="line"></div><div class="line">read_rnd_buffer_size = 8M </div><div class="line"><span class="comment"># MySQL的随机读缓冲区大小。当按任意顺序读取行时(例如，按照排序顺序)，将分配一个随机读缓存区。进行排序查询时， </span></div><div class="line"><span class="comment"># MySQL会首先扫描一遍该缓冲，以避免磁盘搜索，提高查询速度，如果需要排序大量数据，可适当调高该值。但MySQL会为每个客户连接发放该缓冲空间，所以应尽量适当设置该值，以避免内存开销过大 </span></div><div class="line"></div><div class="line">sort_buffer_size = 8M </div><div class="line"><span class="comment"># MySQL执行排序使用的缓冲大小。如果想要增加ORDER BY的速度，首先看是否可以让MySQL使用索引而不是额外的排序阶段。 </span></div><div class="line"><span class="comment"># 如果不能，可以尝试增加sort_buffer_size变量的大小 </span></div><div class="line"></div><div class="line">join_buffer_size = 8M </div><div class="line"><span class="comment"># 联合查询操作所能使用的缓冲区大小，和sort_buffer_size一样，该参数对应的分配内存也是每连接独享 </span></div><div class="line"></div><div class="line">thread_cache_size = 8 </div><div class="line"><span class="comment"># 这个值（默认8）表示可以重新利用保存在缓存中线程的数量，当断开连接时如果缓存中还有空间，那么客户端的线程将被放到缓存中， </span></div><div class="line"><span class="comment"># 如果线程重新被请求，那么请求将从缓存中读取,如果缓存中是空的或者是新的请求，那么这个线程将被重新创建,如果有很多新的线程， </span></div><div class="line"><span class="comment"># 增加这个值可以改善系统性能.通过比较Connections和Threads_created状态的变量，可以看到这个变量的作用。(–&gt;表示要调整的值) </span></div><div class="line"><span class="comment"># 根据物理内存设置规则如下： </span></div><div class="line"><span class="comment"># 1G —&gt; 8 </span></div><div class="line"><span class="comment"># 2G —&gt; 16 </span></div><div class="line"><span class="comment"># 3G —&gt; 32 </span></div><div class="line"><span class="comment"># 大于3G —&gt; 64 </span></div><div class="line"></div><div class="line">query_cache_size = 8M </div><div class="line"><span class="comment">#MySQL的查询缓冲大小（从4.0.1开始，MySQL提供了查询缓冲机制）使用查询缓冲，MySQL将SELECT语句和查询结果存放在缓冲区中， </span></div><div class="line"><span class="comment"># 今后对于同样的SELECT语句（区分大小写），将直接从缓冲区中读取结果。根据MySQL用户手册，使用查询缓冲最多可以达到238%的效率。 </span></div><div class="line"><span class="comment"># 通过检查状态值'Qcache_%'，可以知道query_cache_size设置是否合理：如果Qcache_lowmem_prunes的值非常大，则表明经常出现缓冲不够的情况， </span></div><div class="line"><span class="comment"># 如果Qcache_hits的值也非常大，则表明查询缓冲使用非常频繁，此时需要增加缓冲大小；如果Qcache_hits的值不大，则表明你的查询重复率很低， </span></div><div class="line"><span class="comment"># 这种情况下使用查询缓冲反而会影响效率，那么可以考虑不用查询缓冲。此外，在SELECT语句中加入SQL_NO_CACHE可以明确表示不使用查询缓冲 </span></div><div class="line"></div><div class="line">query_cache_limit = 2M </div><div class="line"><span class="comment">#指定单个查询能够使用的缓冲区大小，默认1M </span></div><div class="line"></div><div class="line">key_buffer_size = 4M </div><div class="line"><span class="comment">#指定用于索引的缓冲区大小，增加它可得到更好处理的索引(对所有读和多重写)，到你能负担得起那样多。如果你使它太大， </span></div><div class="line"><span class="comment"># 系统将开始换页并且真的变慢了。对于内存在4GB左右的服务器该参数可设置为384M或512M。通过检查状态值Key_read_requests和Key_reads， </span></div><div class="line"><span class="comment"># 可以知道key_buffer_size设置是否合理。比例key_reads/key_read_requests应该尽可能的低， </span></div><div class="line"><span class="comment"># 至少是1:100，1:1000更好(上述状态值可以使用SHOW STATUS LIKE 'key_read%'获得)。注意：该参数值设置的过大反而会是服务器整体效率降低 </span></div><div class="line"></div><div class="line">ft_min_word_len = 4 </div><div class="line"><span class="comment"># 分词词汇最小长度，默认4 </span></div><div class="line"></div><div class="line">transaction_isolation = REPEATABLE-READ </div><div class="line"><span class="comment"># MySQL支持4种事务隔离级别，他们分别是： </span></div><div class="line"><span class="comment"># READ-UNCOMMITTED, READ-COMMITTED, REPEATABLE-READ, SERIALIZABLE. </span></div><div class="line"><span class="comment"># 如没有指定，MySQL默认采用的是REPEATABLE-READ，ORACLE默认的是READ-COMMITTED </span></div><div class="line"></div><div class="line">log_bin = mysql-bin </div><div class="line">binlog_format = mixed </div><div class="line">expire_logs_days = 30 <span class="comment">#超过30天的binlog删除 </span></div><div class="line"></div><div class="line">log_error = /data/mysql/mysql-error.log <span class="comment">#错误日志路径 </span></div><div class="line">slow_query_log = 1 </div><div class="line">long_query_time = 1 <span class="comment">#慢查询时间 超过1秒则为慢查询 </span></div><div class="line">slow_query_log_file = /data/mysql/mysql-slow.log </div><div class="line"></div><div class="line">performance_schema = 0 </div><div class="line">explicit_defaults_for_timestamp </div><div class="line"></div><div class="line"><span class="comment">#lower_case_table_names = 1 #不区分大小写 </span></div><div class="line"></div><div class="line">skip-external-locking <span class="comment">#MySQL选项以避免外部锁定。该选项默认开启 </span></div><div class="line"></div><div class="line">default-storage-engine = InnoDB <span class="comment">#默认存储引擎 </span></div><div class="line"></div><div class="line">innodb_file_per_table = 1 </div><div class="line"><span class="comment"># InnoDB为独立表空间模式，每个数据库的每个表都会生成一个数据空间 </span></div><div class="line"><span class="comment"># 独立表空间优点： </span></div><div class="line"><span class="comment"># 1．每个表都有自已独立的表空间。 </span></div><div class="line"><span class="comment"># 2．每个表的数据和索引都会存在自已的表空间中。 </span></div><div class="line"><span class="comment"># 3．可以实现单表在不同的数据库中移动。 </span></div><div class="line"><span class="comment"># 4．空间可以回收（除drop table操作处，表空不能自已回收） </span></div><div class="line"><span class="comment"># 缺点： </span></div><div class="line"><span class="comment"># 单表增加过大，如超过100G </span></div><div class="line"><span class="comment"># 结论： </span></div><div class="line"><span class="comment"># 共享表空间在Insert操作上少有优势。其它都没独立表空间表现好。当启用独立表空间时，请合理调整：innodb_open_files </span></div><div class="line"></div><div class="line">innodb_open_files = 500 </div><div class="line"><span class="comment"># 限制Innodb能打开的表的数据，如果库里的表特别多的情况，请增加这个。这个值默认是300 </span></div><div class="line"></div><div class="line">innodb_buffer_pool_size = 64M </div><div class="line"><span class="comment"># InnoDB使用一个缓冲池来保存索引和原始数据, 不像MyISAM. </span></div><div class="line"><span class="comment"># 这里你设置越大,你在存取表里面数据时所需要的磁盘I/O越少. </span></div><div class="line"><span class="comment"># 在一个独立使用的数据库服务器上,你可以设置这个变量到服务器物理内存大小的80% </span></div><div class="line"><span class="comment"># 不要设置过大,否则,由于物理内存的竞争可能导致操作系统的换页颠簸. </span></div><div class="line"><span class="comment"># 注意在32位系统上你每个进程可能被限制在 2-3.5G 用户层面内存限制, </span></div><div class="line"><span class="comment"># 所以不要设置的太高. </span></div><div class="line"></div><div class="line">innodb_write_io_threads = 4 </div><div class="line">innodb_read_io_threads = 4 </div><div class="line"><span class="comment"># innodb使用后台线程处理数据页上的读写 I/O(输入输出)请求,根据你的 CPU 核数来更改,默认是4 </span></div><div class="line"><span class="comment"># 注:这两个参数不支持动态改变,需要把该参数加入到my.cnf里，修改完后重启MySQL服务,允许值的范围从 1-64 </span></div><div class="line"></div><div class="line">innodb_thread_concurrency = 0 </div><div class="line"><span class="comment"># 默认设置为 0,表示不限制并发数，这里推荐设置为0，更好去发挥CPU多核处理能力，提高并发量 </span></div><div class="line"></div><div class="line">innodb_purge_threads = 1 </div><div class="line"><span class="comment"># InnoDB中的清除操作是一类定期回收无用数据的操作。在之前的几个版本中，清除操作是主线程的一部分，这意味着运行时它可能会堵塞其它的数据库操作。 </span></div><div class="line"><span class="comment"># 从MySQL5.5.X版本开始，该操作运行于独立的线程中,并支持更多的并发数。用户可通过设置innodb_purge_threads配置参数来选择清除操作是否使用单 </span></div><div class="line"><span class="comment"># 独线程,默认情况下参数设置为0(不使用单独线程),设置为 1 时表示使用单独的清除线程。建议为1 </span></div><div class="line"></div><div class="line">innodb_flush_log_at_trx_commit = 2 </div><div class="line"><span class="comment"># 0：如果innodb_flush_log_at_trx_commit的值为0,log buffer每秒就会被刷写日志文件到磁盘，提交事务的时候不做任何操作（执行是由mysql的master thread线程来执行的。 </span></div><div class="line"><span class="comment"># 主线程中每秒会将重做日志缓冲写入磁盘的重做日志文件(REDO LOG)中。不论事务是否已经提交）默认的日志文件是ib_logfile0,ib_logfile1 </span></div><div class="line"><span class="comment"># 1：当设为默认值1的时候，每次提交事务的时候，都会将log buffer刷写到日志。 </span></div><div class="line"><span class="comment"># 2：如果设为2,每次提交事务都会写日志，但并不会执行刷的操作。每秒定时会刷到日志文件。要注意的是，并不能保证100%每秒一定都会刷到磁盘，这要取决于进程的调度。 </span></div><div class="line"><span class="comment"># 每次事务提交的时候将数据写入事务日志，而这里的写入仅是调用了文件系统的写入操作，而文件系统是有 缓存的，所以这个写入并不能保证数据已经写入到物理磁盘 </span></div><div class="line"><span class="comment"># 默认值1是为了保证完整的ACID。当然，你可以将这个配置项设为1以外的值来换取更高的性能，但是在系统崩溃的时候，你将会丢失1秒的数据。 </span></div><div class="line"><span class="comment"># 设为0的话，mysqld进程崩溃的时候，就会丢失最后1秒的事务。设为2,只有在操作系统崩溃或者断电的时候才会丢失最后1秒的数据。InnoDB在做恢复的时候会忽略这个值。 </span></div><div class="line"><span class="comment"># 总结 </span></div><div class="line"><span class="comment"># 设为1当然是最安全的，但性能页是最差的（相对其他两个参数而言，但不是不能接受）。如果对数据一致性和完整性要求不高，完全可以设为2，如果只最求性能，例如高并发写的日志服务器，设为0来获得更高性能 </span></div><div class="line"></div><div class="line">innodb_log_buffer_size = 2M </div><div class="line"><span class="comment"># 此参数确定些日志文件所用的内存大小，以M为单位。缓冲区更大能提高性能，但意外的故障将会丢失数据。MySQL开发人员建议设置为1－8M之间 </span></div><div class="line"></div><div class="line">innodb_log_file_size = 32M </div><div class="line"><span class="comment"># 此参数确定数据日志文件的大小，更大的设置可以提高性能，但也会增加恢复故障数据库所需的时间 </span></div><div class="line"></div><div class="line">innodb_log_files_in_group = 3 </div><div class="line"><span class="comment"># 为提高性能，MySQL可以以循环方式将日志文件写到多个文件。推荐设置为3 </span></div><div class="line"></div><div class="line">innodb_max_dirty_pages_pct = 90 </div><div class="line"><span class="comment"># innodb主线程刷新缓存池中的数据，使脏数据比例小于90% </span></div><div class="line"></div><div class="line">innodb_lock_wait_timeout = 120 </div><div class="line"><span class="comment"># InnoDB事务在被回滚之前可以等待一个锁定的超时秒数。InnoDB在它自己的锁定表中自动检测事务死锁并且回滚事务。InnoDB用LOCK TABLES语句注意到锁定设置。默认值是50秒 </span></div><div class="line"></div><div class="line">bulk_insert_buffer_size = 8M </div><div class="line"><span class="comment"># 批量插入缓存大小， 这个参数是针对MyISAM存储引擎来说的。适用于在一次性插入100-1000+条记录时， 提高效率。默认值是8M。可以针对数据量的大小，翻倍增加。 </span></div><div class="line"></div><div class="line">myisam_sort_buffer_size = 8M </div><div class="line"><span class="comment"># MyISAM设置恢复表之时使用的缓冲区的尺寸，当在REPAIR TABLE或用CREATE INDEX创建索引或ALTER TABLE过程中排序 MyISAM索引分配的缓冲区 </span></div><div class="line"></div><div class="line">myisam_max_sort_file_size = 10G </div><div class="line"><span class="comment"># 如果临时文件会变得超过索引，不要使用快速排序索引方法来创建一个索引。注释：这个参数以字节的形式给出 </span></div><div class="line"></div><div class="line">myisam_repair_threads = 1 </div><div class="line"><span class="comment"># 如果该值大于1，在Repair by sorting过程中并行创建MyISAM表索引(每个索引在自己的线程内) </span></div><div class="line"></div><div class="line">interactive_timeout = 28800 </div><div class="line"><span class="comment"># 服务器关闭交互式连接前等待活动的秒数。交互式客户端定义为在mysql_real_connect()中使用CLIENT_INTERACTIVE选项的客户端。默认值：28800秒（8小时） </span></div><div class="line"></div><div class="line">wait_timeout = 28800 </div><div class="line"><span class="comment"># 服务器关闭非交互连接之前等待活动的秒数。在线程启动时，根据全局wait_timeout值或全局interactive_timeout值初始化会话wait_timeout值， </span></div><div class="line"><span class="comment"># 取决于客户端类型(由mysql_real_connect()的连接选项CLIENT_INTERACTIVE定义)。参数默认值：28800秒（8小时） </span></div><div class="line"><span class="comment"># MySQL服务器所支持的最大连接数是有上限的，因为每个连接的建立都会消耗内存，因此我们希望客户端在连接到MySQL Server处理完相应的操作后， </span></div><div class="line"><span class="comment"># 应该断开连接并释放占用的内存。如果你的MySQL Server有大量的闲置连接，他们不仅会白白消耗内存，而且如果连接一直在累加而不断开， </span></div><div class="line"><span class="comment"># 最终肯定会达到MySQL Server的连接上限数，这会报'too many connections'的错误。对于wait_timeout的值设定，应该根据系统的运行情况来判断。 </span></div><div class="line"><span class="comment"># 在系统运行一段时间后，可以通过show processlist命令查看当前系统的连接状态，如果发现有大量的sleep状态的连接进程，则说明该参数设置的过大， </span></div><div class="line"><span class="comment"># 可以进行适当的调整小些。要同时设置interactive_timeout和wait_timeout才会生效。 </span></div><div class="line"></div><div class="line">[mysqldump] </div><div class="line">quick </div><div class="line">max_allowed_packet = 16M <span class="comment">#服务器发送和接受的最大包长度 </span></div><div class="line"></div><div class="line">[myisamchk] </div><div class="line">key_buffer_size = 8M </div><div class="line">sort_buffer_size = 8M </div><div class="line">read_buffer = 4M </div><div class="line">write_buffer = 4M</div></pre></td></tr></table></figure>
	

	

</article>




	<article>
	
		<h1><a href="/2017/10/12/MySQL/6. MySQL调优/">MySQL调优</a></h1>
	
	<div class="article__infos">
		<span class="article__date">2017-10-12</span><br />
		
		
			<span class="article__tags">
			  	<a class="article__tag-link" href="/tags/MySQL/">MySQL</a>
			</span>
		
	</div>

	

	
		<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;MySQL调优可以从几个方面来做：</p>
<h2 id="架构层："><a href="#架构层：" class="headerlink" title="架构层："></a>架构层：</h2><p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;做从库，实现读写分离；</p>
<h2 id="系统层次："><a href="#系统层次：" class="headerlink" title="系统层次："></a>系统层次：</h2><ul>
<li>增加内存；</li>
<li>给磁盘做raid0或者raid5以增加磁盘的读写速度；</li>
<li>可以重新挂载磁盘，并加上noatime参数，这样可以减少磁盘的i/o;</li>
</ul>
<h2 id="MySQL本身调优："><a href="#MySQL本身调优：" class="headerlink" title="MySQL本身调优："></a>MySQL本身调优：</h2><ul>
<li>如果未配置主从同步，可以把bin-log功能关闭，减少磁盘i/o</li>
<li>在my.cnf中加上skip-name-resolve,这样可以避免由于解析主机名延迟造成mysql执行慢</li>
<li>调整几个关键的buffer和cache。调整的依据，主要根据数据库的状态来调试。如何调优可以参考5.</li>
</ul>
<h2 id="应用层次："><a href="#应用层次：" class="headerlink" title="应用层次："></a>应用层次：</h2><p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;查看慢查询日志，根据慢查询日志优化程序中的SQL语句，比如增加索引</p>
<h2 id="调整几个关键的buffer和cache"><a href="#调整几个关键的buffer和cache" class="headerlink" title="调整几个关键的buffer和cache"></a>调整几个关键的buffer和cache</h2><ol>
<li><p>key_buffer_size  首先可以根据系统的内存大小设定它，大概的一个参考值：1G以下内存设定128M；2G/256M; 4G/384M;8G/1024M；16G/2048M.这个值可以通过检查状态值Key_read_requests和 Key_reads,可以知道key_buffer_size设置是否合理。比例key_reads / key_read_requests应该尽可能的低，至少是1:100，1:1000更好(上述状态值可以使用SHOW STATUS LIKE ‘key_read%’获得)。注意：该参数值设置的过大反而 会是服务器整体效率降低!</p>
</li>
<li><p>table_open_cache 打开一个表的时候，会临时把表里面的数据放到这部分内存中，一般设置成1024就够了，它的大小我们可以通过这样的方法来衡量： 如果你发现 open_tables等于table_cache，并且opened_tables在不断增长，那么你就需要增加table_cache的值了(上述状态值可以使用SHOW STATUS LIKE ‘Open%tables’获得)。注意，不能盲目地把table_cache设置成很大的值。如果设置得太高，可能会造成文件描述符不足，从而造成性能不稳定或者连接失败。</p>
</li>
<li><p>sort_buffer_size 查询排序时所能使用的缓冲区大小,该参数对应的分配内存是每连接独占!如果有100个连接，那么实际分配的总共排序缓冲区大小为100 × 4 = 400MB。所以，对于内存在4GB左右的服务器推荐设置为4-8M。</p>
</li>
<li><p>read_buffer_size 读查询操作所能使用的缓冲区大小。和sort_buffer_size一样，该参数对应的分配内存也是每连接独享!</p>
</li>
<li><p>join_buffer_size 联合查询操作所能使用的缓冲区大小，和sort_buffer_size一样，该参数对应的分配内存也是每连接独享!</p>
</li>
<li><p>myisam_sort_buffer_size 这个缓冲区主要用于修复表过程中排序索引使用的内存或者是建立索引时排序索引用到的内存大小，一般4G内存给64M即可。</p>
</li>
<li><p>query_cache_size MySQL查询操作缓冲区的大小，通过以下做法调整：SHOW STATUS LIKE ‘Qcache%’; 如果Qcache_lowmem_prunes该参数记录有多少条查询因为内存不足而被移除出查询缓存。通过这个值，用户可以适当的调整缓存大小。如果该值非常大，则表明经常出现缓冲不够的情况，需要增加缓存大小;Qcache_free_memory:查询缓存的内存大小，通过这个参数可以很清晰的知道当前系统的查询内存是否够用，是多了，还是不够用，我们可以根据实际情况做出调整。一般情况下4G内存设置64M足够了。</p>
</li>
<li><p>thread_cache_size 表示可以重新利用保存在缓存中线程的数，参考如下值：   1G  —&gt; 8 2G  —&gt; 16 3G  —&gt; 32  &gt;3G  —&gt; 64<br> 除此之外，还有几个比较关键的参数：</p>
</li>
<li><p>thread_concurrency 这个值设置为cpu核数的2倍即可</p>
</li>
<li><p>wait_timeout 表示空闲的连接超时时间，默认是28800s，这个参数是和  interactive_timeout一起使用的，也就是说要想让wait_timeout 生效，必须同时设置 interactive_timeout，建议他们两个都设置为10</p>
</li>
<li><p>max_connect_errors 是一个MySQL中与安全有关的计数器值，它负责阻止过多尝试失败的客户端以防止暴力破解密码的情况。与性能并无太大关系。为了避免一些错误我们一般都设置比较大，比如说10000 </p>
</li>
<li><p>max_connections 最大的连接数，根据业务请求量适当调整，设置500足够</p>
</li>
<li><p>max_user_connections 是指同一个账号能够同时连接到mysql服务的最大连接数。设置为0表示不限制。通常我们设置为100足够 </p>
</li>
</ol>

	

	

</article>




	<article>
	
		<h1><a href="/2017/10/12/MySQL/5. MySQL配置讲解/">MySQL配置讲解</a></h1>
	
	<div class="article__infos">
		<span class="article__date">2017-10-12</span><br />
		
		
			<span class="article__tags">
			  	<a class="article__tag-link" href="/tags/MySQL/">MySQL</a>
			</span>
		
	</div>

	

	
		<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;mysql 安装好后，是从安装包的 support-files 里面复制过来一个模板配置文件，默认 mysql 配置文件是在 /etc/my.cnf 下，其实这个路径或者文件名字是可以修改的，在启动脚本中修改。</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div></pre></td><td class="code"><pre><div class="line">[mysqld]</div><div class="line">socket = /tmp/mysql.sock</div></pre></td></tr></table></figure>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;为 MySQL 客户程序与服务器之间的本地通信指定一个套接字文件（ linux 下默认是 /var/lib/mysql/mysql.sock ）</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">port = 3306</div></pre></td></tr></table></figure>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;指定 MySQL 监听的端口</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">skip-name-resolve</div></pre></td></tr></table></figure>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;禁止 MySQL 对外部连续进行 DNS 解析，使用这一选项可以消除 MySQL 进行 DNS 解析的时间。但需要注意，如果开启选项，则所有远程主机连接授权都要使用 IP 地址方式，否则 MySQL 将无法正常处理连接请求。</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">key_buffer_size = 384M</div></pre></td></tr></table></figure>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;key_buffer 是用于索引块的缓冲区大小，增加它可得到更好处理的索引（对所有读和多重写）。索引被所有的线程共享， key_buffer 的大小视内存大小而定。（增加该值可以得到更好的处理索引的速度，一般1G内存设置256M）</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">table_open_cache = 512</div></pre></td></tr></table></figure>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; MySQL 每打开一个表，都会读入一些数据到 table_open_cache 缓存中，当 MySQL 在这个缓存中找不到相应信息时，才会去磁盘上读取。默认值 64 ，假定系统有200的并发连接，则需将此参数设置为 200*N （N 为每个连接所需的文件描述符数目）：当把 table_open_cache 设置为很大时，如果系统处理不了那么多文件描述符，那么就会出现客户端失效，连接补上。</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">max_allowed_packet = 16M</div></pre></td></tr></table></figure>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;接受的数据包大小；增加该变量的值十分安全，这是因为仅当需要时才会分配额外内存。例如，仅当发出长查询或 MySQLd 必须返回大的结果行时才会分配更多内存。该变量之所以取较小默认值是一种预防措施，以捕获客户端和服务器之间的错误信息包，并确保不会因偶然使用大的信息包而导致内存溢出。</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">sort_buffer_size = 1M</div></pre></td></tr></table></figure>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;MySQL 执行排序使用缓冲大小。如果想要增加ORDER BY 的速度，首先看看是否可以让 MySQL  使用索引而不是额外的排序阶段。如果不能，可以尝试增加 sort_buffer_size 变量的大小。</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">read_buffer_size = 2M</div></pre></td></tr></table></figure>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;读查询操作所能使用的缓冲区大小。和 sort_buffer_size 一样，该参数对应的分配内存也是每连接独享。对表进行顺序扫描的请求将分配一个读入缓冲区， MySQL 会为它分配一段内容缓冲区。如果对表的顺序扫描请求非常频繁，并且任位频繁扫描进行得太慢，可以通过增加该变量值以及内存缓冲区大小提高其性能。</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">join_buffer_size = 2M</div></pre></td></tr></table></figure>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;联合查询操作所能使用的缓冲区大小，和 sort_buffer_size 一样，该参数对应的分配内存也是每连接独享。</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">query_cache_size = 32M</div></pre></td></tr></table></figure>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;指定 MySQL 查询结果缓冲区的大小。</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">read_rnd_buffer_size = 8M</div></pre></td></tr></table></figure>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;随机读缓冲区大小。当按任意顺序读取行时（例如，按照排序顺序），将分配一个随机读缓冲区。进行排序查询时， MySQL 会首先扫描一遍该缓冲，以比秒磁盘搜索，提高查询速度，如果需要排序大量数据，可适当调高该值。但 MySQL 会为每个客户连接发放该缓冲空间，所以应尽量适当设置该值，以避免内存开销过大。</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">myisam_sort_buffer_size = 64M</div></pre></td></tr></table></figure>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;MyISAM表发生变化时重新排序所需的缓冲。</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">thread_concurrency = 8</div></pre></td></tr></table></figure>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;最大并发线程数，取值为服务器逻辑 CPU 数量 ×2</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">thread_cache_size = 8</div></pre></td></tr></table></figure>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;该值表示可以重新利用保存在缓存中线程的数量，当断开连接时若缓存中还有空间，那么客户端的线程将被放到缓存中，如果线程重新被请求，那么请求将从缓存中读取，如果缓存中是空的或者是新的请求，那么线程将被重新创建。设置规律为：1G内存设置为8，2G内存设置为16，4G内存以上设置为64</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">max_connections = 1000</div></pre></td></tr></table></figure>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;MySQL 的最大连接数，如果服务器的并发连接请求量比较大，建立调高此值，以增加并行连接数量，当然这建立在机器能支撑的情况下，因为如果连接数越多，介于 MySQL 会为每个连接提供连接缓冲区，就会开销越多的内存，所以要适当调整该值，不能盲目提高设值。可以过 ‘conn%’ 通配符查看当前状态的连接数量，以定夺该值的大小。</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">max_connect_errors = 6000</div></pre></td></tr></table></figure>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;对于同一主机，如果有超出该参数值个数的中断错误连接，则该主机将被禁止连接。如需对该主机进行解禁，执行 FLUSH HOST</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">open_files_limit = 65535</div></pre></td></tr></table></figure>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;MySQL 打开的文件描述符限制，默认大小1024</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">skip-locking</div></pre></td></tr></table></figure>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;避免 MySQL 的外部锁定，减少出错几率增强稳定性。（是否要过滤掉 lock 为了让它更快一点可以把锁过滤掉）</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">wait_timeout = 8</div></pre></td></tr></table></figure>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;表示空闲的连接超时时间，默认是28800s，这个参数是和 interactive_timeout 一起使用的，也就是说要想让 wait_timeout 生效，必须同时设置 interactive_timeout </p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div></pre></td><td class="code"><pre><div class="line">interactive_timeout = 8</div><div class="line">long_query_time = 1</div></pre></td></tr></table></figure>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;慢查询入职的超时时间</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">log_slow_queries = /path/to/slow_queries</div></pre></td></tr></table></figure>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;慢查询日志路径，必须配合上面的参数一同使用</p>

	

	

</article>




	<article>
	
		<h1><a href="/2017/10/12/MySQL/38. MySQL插入一条数据竟然耗时100ms/">MySQL插入一条数据竟然耗时100ms</a></h1>
	
	<div class="article__infos">
		<span class="article__date">2017-10-12</span><br />
		
		
			<span class="article__tags">
			  	<a class="article__tag-link" href="/tags/MySQL/">MySQL</a>
			</span>
		
	</div>

	

	
		<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;数据引擎为innodb，数据量并没有多大，理论上插入一条数据也就几ms。磁盘IO、内存占用以及cpu使用都没有问题。所以想到是某个参数设置不当导致。查资料，发现可以设置一个参数 </p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">innodb_flush_log_at_trx_commit = 2</div></pre></td></tr></table></figure>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;插入速度立马变快。  这个参数有什么意义？ </p>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;该参数取值可以是0,1,2。</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">innodb_flush_log_at_trx_commit = 0</div></pre></td></tr></table></figure>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;innodb 中的Log Thread 每隔1 秒钟会将log buffer中的数据写入到文件，同时还会通知文件系统进行文件同步的flush操作，保证数据确实已经写入到磁盘上面的物理文件。但是，每次事务的结束（commit 或者是rollback）并不会触发Log Thread 将log buffer 中的数据写入文件。所以，当设置为0 的时候，当MySQL Crash 和OS Crash 或者主机断电之后，最极端的情况是丢失1 秒时间的数据变更。</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">innodb_flush_log_at_trx_commit = 1</div></pre></td></tr></table></figure>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;这也是innodb 的默认设置。我们每次事务的结束都会触发Log Thread 将log buffer 中的数据写入文件并通知文件系统同步文件。这个设置是最安全的设置，能够保证不论是MySQL Crash 还是OS Crash 或者是主机断电都不会丢失任何已经提交的数据。</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">innodb_flush_log_at_trx_commit = 2</div></pre></td></tr></table></figure>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;当我们设置为2 的时候，Log Thread 会在我们每次事务结束的时候将数据写入事务日志，但是这里的写入仅仅是调用了文件系统的文件写入操作。而我们的文件系统都是有缓存机制的，所以Log Thread 的这个写入并不能保证内容真的已经写入到物理磁盘上面完成持久化的动作。文件系统什么时候会将缓存中的这个数据同步到物理磁盘文件Log Thread 就完全不知道了。所以，当设置为2 的时候，MySQL Crash 并不会造成数据的丢失，但是OS Crash 或者是主机断电后可能丢失的数据量就完全取决于文件系统了。</p>

	

	

</article>




	<article>
	
		<h1><a href="/2017/10/12/MySQL/4. MySQL5.7 二进制源码包安装/">MySQL5.7 二进制源码包安装</a></h1>
	
	<div class="article__infos">
		<span class="article__date">2017-10-12</span><br />
		
		
			<span class="article__tags">
			  	<a class="article__tag-link" href="/tags/MySQL/">MySQL</a>
			</span>
		
	</div>

	

	
		<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;一般平时安装MySQL都是源码包安装的，但是由于它的编译需要很长的时间，所以建议安装二进制免编译包。可以到<a href="http://dev.mysql.com/downloads" target="_blank" rel="external">MySQL官方网站</a>去下载，也可以到<a href="http://syslab.comsenz.com/downloads/linux/" target="_blank" rel="external">comsenz官方网站</a>下载，还有各大镜像站下载。</p>
<h2 id="下载安装包，并安装依赖包"><a href="#下载安装包，并安装依赖包" class="headerlink" title="下载安装包，并安装依赖包"></a>下载安装包，并安装依赖包</h2><figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div></pre></td><td class="code"><pre><div class="line">wget http://mirrors.sohu.com/mysql/MySQL-5.7/mysql-5.7.12-linux-glibc2.5-x86_64.tar.gz</div><div class="line">yum -y install gcc-c++ ncurses-devel cmake make perl gcc autoconf automake zlib libxml libgcrypt libtool bison</div></pre></td></tr></table></figure>
<h2 id="解压"><a href="#解压" class="headerlink" title="解压"></a>解压</h2><figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div></pre></td><td class="code"><pre><div class="line">tar zxvf mysql-5.7.12-linux-glibc2.5-x86_64.tar.gz</div><div class="line">mv mysql-5.7.12-linux-glibc2.5-x86_64 /usr/<span class="built_in">local</span>/mysql</div></pre></td></tr></table></figure>
<h2 id="初始化"><a href="#初始化" class="headerlink" title="初始化"></a>初始化</h2><figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div></pre></td><td class="code"><pre><div class="line">useradd -M -s /sbin/nologin mysql </div><div class="line">mkdir -p /data/mysql</div><div class="line">chown mysql /data/mysql</div><div class="line"><span class="built_in">cd</span> /usr/<span class="built_in">local</span>/mysql</div><div class="line">./bin/mysqld --initialize --user=mysql --datadir=/data/mysql</div></pre></td></tr></table></figure>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;注意，这一步最后一行会有一个提示</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">[Note] A temporary password is generated <span class="keyword">for</span> root@localhost: B*s1i(*,kXwg</div></pre></td></tr></table></figure>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;最后面的字符串为root密码</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">./bin/mysql_ssl_rsa_setup --datadir=/data/mysql</div></pre></td></tr></table></figure>
<h2 id="拷贝配置文件和启动脚本"><a href="#拷贝配置文件和启动脚本" class="headerlink" title="拷贝配置文件和启动脚本"></a>拷贝配置文件和启动脚本</h2><figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div></pre></td><td class="code"><pre><div class="line">cp support-files/my-default.cnf /etc/my.cnf </div><div class="line">vim /etc/my.cnf //编辑或者修改</div><div class="line">basedir = /usr/<span class="built_in">local</span>/mysql</div><div class="line">datadir = /data/mysql</div><div class="line">port = 3306</div><div class="line">socket = /tmp/mysql.sock</div><div class="line"></div><div class="line">cp support-files/mysql.server /etc/init.d/mysqld</div><div class="line">vi /etc/init.d/mysqld //编辑或者修改</div><div class="line">basedir=/usr/<span class="built_in">local</span>/mysql</div><div class="line">datadir=/data/mysql</div></pre></td></tr></table></figure>
<h2 id="启动服务"><a href="#启动服务" class="headerlink" title="启动服务"></a>启动服务</h2><figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">/etc/init.d/mysqld start</div></pre></td></tr></table></figure>
<h2 id="设置root密码"><a href="#设置root密码" class="headerlink" title="设置root密码"></a>设置root密码</h2><p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;使用初始化密码登录</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div></pre></td><td class="code"><pre><div class="line">/usr/<span class="built_in">local</span>/mysql/bin/mysql -uroot -p<span class="string">'B*s1i(*,kXwg'</span> //进入后直接设置密码</div><div class="line">mysql&gt;<span class="built_in">set</span> password = password(<span class="string">'mypass'</span>); //一定要设置一下新密码</div></pre></td></tr></table></figure>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;退出来，再使用新的密码登录就可以了</p>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;还有一种情况，就是不知道初始化密码</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">vim /etc/my.cnf</div></pre></td></tr></table></figure>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;在 [mysql] 下面增加一行</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">skip-grant-tables</div></pre></td></tr></table></figure>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;重启mysql</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">/etc/init.d/mysqld restart</div></pre></td></tr></table></figure>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;这时登录mysql不需要密码，进入mysql重新设置root密码</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div></pre></td><td class="code"><pre><div class="line">/usr/<span class="built_in">local</span>/mysql/bin/mysql -uroot </div><div class="line">mysql&gt; update user <span class="built_in">set</span> authentication_string=password(<span class="string">'123333'</span>) <span class="built_in">where</span> user=<span class="string">'root'</span>;</div></pre></td></tr></table></figure>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;退出来后，更改my.cnf，去掉刚加的skip-grant-tables</p>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;再次重启mysql</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">/etc/init.d/mysqld restart</div></pre></td></tr></table></figure>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;此时就可以使用新的密码登录了。</p>

	

	

</article>




	<article>
	
		<h1><a href="/2017/10/12/MySQL/37. 数据库死锁原理及解决思路/">数据库死锁原理及解决思路</a></h1>
	
	<div class="article__infos">
		<span class="article__date">2017-10-12</span><br />
		
		
			<span class="article__tags">
			  	<a class="article__tag-link" href="/tags/MySQL/">MySQL</a>
			</span>
		
	</div>

	

	
		<h2 id="一、什么是锁？"><a href="#一、什么是锁？" class="headerlink" title="一、什么是锁？"></a>一、什么是锁？</h2><p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;数据库是一个多用户使用的共享资源。当多个用户并发地存取数据时，在数据库中就会产生多个事务同时存取同一数据的情况。若对并发操作不加控制就可能会读取和存储不正确的数据，破坏数据库的一致性。</p>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;加锁的目的确保并发更新场景下的数据正确性。当事务在对某个数据对象进行操作前，先向系统发出请求，对其加锁。加锁后事务就对该数据对象有了一定的控制，在该事务释放锁之前，其他的事务不能对此数据对象进行更新操作。</p>
<h3 id="1-锁的持有周期"><a href="#1-锁的持有周期" class="headerlink" title="1.锁的持有周期"></a>1.锁的持有周期</h3><p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;加锁：实际访问到某个待更新的行时，对其加锁（而非一开始就将所有的锁都一次性持有）</p>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;解锁：事务提交/回滚时（而非语句结束时就释放）</p>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;持有周期就是加锁和解锁之间的实际时间。</p>
<h3 id="2-锁粒度：库、表、页、行"><a href="#2-锁粒度：库、表、页、行" class="headerlink" title="2.锁粒度：库、表、页、行"></a>2.锁粒度：库、表、页、行</h3><p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;锁的粒度越细，并发级别越高（实现也更复杂）</p>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;传统关系型数据库，都实现了行级别的锁</p>
<h3 id="3-常见的加锁操作"><a href="#3-常见的加锁操作" class="headerlink" title="3.常见的加锁操作"></a>3.常见的加锁操作</h3><ul>
<li>–Insert、Delete、Update（毫无疑问）</li>
<li>–Select … lock in share mode、select … for update（显式加锁）</li>
<li>–Lock table … read/write （显示加表级锁）</li>
<li>–Alter table … / Create Index … （DDL操作引入的加锁）</li>
<li>–Flush tables with read lock （备份常用）</li>
<li>–Primary Key/Unique Key唯一约束检查</li>
</ul>
<h3 id="4-常规锁模式"><a href="#4-常规锁模式" class="headerlink" title="4.常规锁模式"></a>4.常规锁模式</h3><p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;共享（S)锁：多个事务可封锁一个共享页；任何事务都不能修改该页； 通常是该页被读取完毕，S锁立即被释放。 </p>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;排它（X)锁：仅允许一个事务封锁此页；其他任何事务必须等到X锁被释放才能对该页进行访问；X锁一直到事务结束才能被释放。 </p>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;更新（U)锁：用来预定要对此页施加X锁，它允许其他事务读，但不允许再施加U锁或X锁；当被读取的页将要被更新时，则升级为X锁；U锁一直到事务结束时才能被释放。</p>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;最容易理解的锁模式，读加共享锁，写加排它锁</p>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;锁的属性</p>
<ul>
<li>LOCK_REC_NOT_GAP（锁记录，1024）</li>
<li>LOCK_GAP（锁记录前的GAP，512）</li>
<li>LOCK_ORDINARY（同时锁记录+记录前的GAP，0。传说中的Next Key锁）</li>
<li>LOCK_INSERT_INTENTION（插入意向锁，2048）</li>
</ul>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;加上LOCK_GAP，一切难以理解的源头（后面重点分析）</p>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;锁组合（属性 + 模式）</p>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;锁的属性可以与锁模式任意组合。例如：LOCK_REC_NOT_GAP（1024） + LOCK_X（3）</p>
<p><figure class="figure"><img src="https://github.com/hcldirgit/image/blob/master/%E6%95%B0%E6%8D%AE%E5%BA%93%E6%AD%BB%E9%94%81%E5%8E%9F%E7%90%86%E5%8F%8A%E8%A7%A3%E5%86%B3%E6%80%9D%E8%B7%AF/01.png?raw=true" alt=""></figure></p>
<h2 id="二、什么又是死锁？"><a href="#二、什么又是死锁？" class="headerlink" title="二、什么又是死锁？"></a>二、什么又是死锁？</h2><p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;死锁发生在当多个事务访问同一数据对象时，其中每个事务拥有的锁都是其他事务所需的，由此造成每个事务都无法继续下去。简单的说，事务A等待事务B释放他的资源，B又等待A释放他的资源，这样就互相等待就形成死锁。</p>
<h2 id="三、产生死锁的原因："><a href="#三、产生死锁的原因：" class="headerlink" title="三、产生死锁的原因："></a>三、产生死锁的原因：</h2><ol>
<li>系统资源不足。</li>
<li>事务运行推进的顺序不合适。<br>3.资源分配不当等。</li>
</ol>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;如果系统资源充足，该事务的资源请求都能够得到满足，死锁出现的可能性就很低，否则就会因争夺有限的资源而陷入死锁。其次，事务运行推进顺序与速度不同，也可能产生死锁。</p>
<h2 id="四、产生死锁的四个必要条件："><a href="#四、产生死锁的四个必要条件：" class="headerlink" title="四、产生死锁的四个必要条件："></a>四、产生死锁的四个必要条件：</h2><p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;只要下面四个条件有一个不具备，系统就不会出现死锁。</p>
<ol>
<li><p>互斥条件。存在多个并发事务（2个或者以上），而某数据对象在一段时间内只能由一个事务占有，不能同时被两个或两个以上的事务占有。如果此时还有其它事务请求该数据对象，则请求者只能等待，直至占有该数据对象的事务用毕释放。</p>
</li>
<li><p>不可抢占条件。该事务所获得的数据对象在未使用完毕之前，其他事务不能强行地从该事务手中获取该数据对象，而只能由该事务自行释放。</p>
</li>
<li><p>占有且申请条件。某事务都已经占有了一个数据对象，为了完成事务逻辑，还必须更新的数据对象，但是此新的数据对象又被其他事务在占用，但是它在等待新数据对象的时候，仍然占有已占有的数据对象。</p>
</li>
<li><p>循环等待条件。存在一个事务等待序列{P1，P2，…，Pn}，其中P1等待P2所占有的某一资源，P2等待P3所占有的某一源，……，而Pn等待P1所占有的的某一资源，形成一个事务循环等待环。</p>
</li>
</ol>
<h2 id="五、如何避免死锁？"><a href="#五、如何避免死锁？" class="headerlink" title="五、如何避免死锁？"></a>五、如何避免死锁？</h2><p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;死锁的关键在于：两个(或以上)的Session加锁的顺序不一致。</p>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;打破上述四个条件中的一个，常见解决思路有以下几中：</p>
<ol>
<li>按同一顺序访问对象。(注：避免出现循环)</li>
<li>避免事务中的用户交互。(注：减少持有资源的时间，较少锁竞争)<br>因为运行没有用户交互的批处理的速度要远远快于用户手动响应查询的速度。</li>
<li>保持事务简短并处于一个批处理中。(注：同(2)，减少持有资源的时间)</li>
<li>使用较低的隔离级别。(注：使用较低的隔离级别（例如已提交读）比使用较高的隔离级别（例如可序列化）持有共享锁的时间更短，减少锁竞争)</li>
<li>使用基于行版本控制的隔离级别</li>
<li>使用绑定连接。</li>
</ol>
<h2 id="六、死锁的排查解决办法（以mysql-innodB为例）"><a href="#六、死锁的排查解决办法（以mysql-innodB为例）" class="headerlink" title="六、死锁的排查解决办法（以mysql innodB为例）"></a>六、死锁的排查解决办法（以mysql innodB为例）</h2><p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;死锁出现的报错信息：“Deadlock found when trying to get lock;”</p>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;如何排查死锁成因。</p>
<ol>
<li>通过应用业务日志定位到问题代码，找到相应的事务对应的sql；</li>
</ol>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;因为死锁被检测到后会回滚，这些信息都会以异常反应在应用的业务日志中，通过这些日志我们可以定位到相应的代码，并把事务的sql给梳理出来。</p>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;命令：</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">show engine innodb status\G;</div></pre></td></tr></table></figure>
<p><figure class="figure"><img src="https://github.com/hcldirgit/image/blob/master/%E6%95%B0%E6%8D%AE%E5%BA%93%E6%AD%BB%E9%94%81%E5%8E%9F%E7%90%86%E5%8F%8A%E8%A7%A3%E5%86%B3%E6%80%9D%E8%B7%AF/02.png?raw=true" alt=""></figure></p>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;一般来说，死锁的原因和处理方式有很多种，主要是数据库系统在设计阶段就要考虑，所以再深入的研究和了解只能专业去研究了，在此不细究。</p>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;锁表</p>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;读锁定</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">mysql&gt;LOCK TABLES tbl_name READ;</div></pre></td></tr></table></figure>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;验证：</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">show OPEN TABLES <span class="built_in">where</span> In_use &gt; 0;  <span class="comment">#查询是否锁表</span></div></pre></td></tr></table></figure>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;写锁定</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">mysql&gt;LOCK TABLES tbl_name WRITE;</div></pre></td></tr></table></figure>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;解锁（有两种）：</p>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;第一种</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">mysql&gt;UNLOCK TABLES;</div></pre></td></tr></table></figure>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;第二种</p>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;步骤：</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div></pre></td><td class="code"><pre><div class="line">mysql -uxxx -pxxx -h服务器ip --port=服务器端口;（如果服务器设置了ip和端口访问的话，一定要带ip和端口）</div><div class="line">show OPEN TABLES <span class="built_in">where</span> In_use &gt; 0;  <span class="comment">#查询是否锁表</span></div><div class="line">SELECT * FROM INFORMATION_SCHEMA.INNODB_LOCKS;   <span class="comment">#查看正在锁的事务</span></div><div class="line">SELECT * FROM INFORMATION_SCHEMA.INNODB_LOCK_WAITS;  <span class="comment">#查看等待锁的事务</span></div><div class="line"></div><div class="line">mysql&gt; show processlist; <span class="comment">#查看正在执行的sql （show full processlist;查看全部sql）</span></div><div class="line">mysql&gt; <span class="built_in">kill</span> id <span class="comment">#杀死sql进程；</span></div></pre></td></tr></table></figure>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;如果进程太多找不到，就重启mysql</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">/ect/init.d/mysql restart</div></pre></td></tr></table></figure>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;或</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div></pre></td><td class="code"><pre><div class="line">/ect/init.d/mysql stop  <span class="comment">#如果关不掉就直接kill -9 进程id </span></div><div class="line">/ect/init.d/mysql start</div></pre></td></tr></table></figure>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;去看看mysql日志文件是否保存死锁日志：</p>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;常用目录：/var/log/mysqld.log；</p>
<h2 id="七、表级锁的加锁和解锁过程（以mysql-innodB为例）"><a href="#七、表级锁的加锁和解锁过程（以mysql-innodB为例）" class="headerlink" title="七、表级锁的加锁和解锁过程（以mysql innodB为例）"></a>七、表级锁的加锁和解锁过程（以mysql innodB为例）</h2><p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;mysql 的 表锁 lock tables 感觉就像一个 封闭的空间</p>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;mysql发现 lock tables 命令的时候,会将带有锁标记的表(table) 带入封闭空间,直到 出现 unlock tables 命令 或 线程结束, 才关闭封闭空间。</p>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;进入封闭空间时 , 仅仅只有锁标记的表(table) 可以在里面使用,其他表无法使用。</p>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;锁标记 分为 read 和 write 下面是 两种 锁的区别</p>
<hr>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;如 将 table1 设为read锁, table2 设为write锁, table3 设为read锁</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">lock tables [table1] <span class="built_in">read</span>,[table2] write,[table3] <span class="built_in">read</span>;</div></pre></td></tr></table></figure>
<hr>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;执行到这里时,进入封闭空间。</p>
<ol>
<li>table1 仅允许[所有人]读,[空间外]如需写、更新要等待[空间退出],[空间内]如需写、更新会引发mysql报错。</li>
<li>table2 仅允许[空间内]读写更新,[空间外]如需写、更新要等待[空间退出]。</li>
<li>table3 仅允许[所有人]读,[空间外]如需写、更新要等待[空间退出],[空间内]如需写、更新会引发mysql报错。</li>
</ol>
<hr>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;执行到这里时,退出封闭空间,释放所有表锁</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">unlock tables</div></pre></td></tr></table></figure>
<hr>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;当前线程关闭时,自动退出封闭空间,释放所有表锁,无论有没有执行 unlock tables</p>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;加锁和解锁（表级锁）：</p>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;实验中用到的命令：</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div></pre></td><td class="code"><pre><div class="line">mysql&gt; show engines;   <span class="comment">#提供什么存储引擎:</span></div><div class="line">mysql&gt; show variables like <span class="string">'%storage_engine%'</span>;  <span class="comment">#当前默认的存储引擎:</span></div></pre></td></tr></table></figure>
<p><figure class="figure"><img src="https://github.com/hcldirgit/image/blob/master/%E6%95%B0%E6%8D%AE%E5%BA%93%E6%AD%BB%E9%94%81%E5%8E%9F%E7%90%86%E5%8F%8A%E8%A7%A3%E5%86%B3%E6%80%9D%E8%B7%AF/03.png?raw=true" alt=""></figure></p>
<p><figure class="figure"><img src="https://github.com/hcldirgit/image/blob/master/%E6%95%B0%E6%8D%AE%E5%BA%93%E6%AD%BB%E9%94%81%E5%8E%9F%E7%90%86%E5%8F%8A%E8%A7%A3%E5%86%B3%E6%80%9D%E8%B7%AF/04.png?raw=true" alt=""></figure></p>
<p><figure class="figure"><img src="https://github.com/hcldirgit/image/blob/master/%E6%95%B0%E6%8D%AE%E5%BA%93%E6%AD%BB%E9%94%81%E5%8E%9F%E7%90%86%E5%8F%8A%E8%A7%A3%E5%86%B3%E6%80%9D%E8%B7%AF/05.png?raw=true" alt=""></figure></p>

	

	

</article>




	<article>
	
		<h1><a href="/2017/10/12/MySQL/36. 使用mysql-proxy 快速实现mysql 集群读写分离/">使用mysql-proxy 快速实现mysql 集群读写分离</a></h1>
	
	<div class="article__infos">
		<span class="article__date">2017-10-12</span><br />
		
		
			<span class="article__tags">
			  	<a class="article__tag-link" href="/tags/MySQL/">MySQL</a>
			</span>
		
	</div>

	

	
		<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;目前较为常见的mysql读写分离分为两种： </p>
<ol>
<li><p>基于程序代码内部实现：在代码中对select操作分发到从库；其它操作由主库执行；这类方法也是目前生产环境应用最广泛，知名的如DISCUZ X2。优点是性能较好，因为在程序代码中实现，不需要增加额外的设备作为硬件开支。缺点是需要开发人员来实现，运维人员无从下手。 </p>
</li>
<li><p>基于中间代理层实现：我们都知道代理一般是位于客户端和服务器之间，代理服务器接到客户端请求后通过判断然后转发到后端数据库。在这有两个代表性程序</p>
</li>
</ol>
<p><figure class="figure"><img src="https://github.com/hcldirgit/image/blob/master/%E4%BD%BF%E7%94%A8mysql-proxy%20%E5%BF%AB%E9%80%9F%E5%AE%9E%E7%8E%B0mysql%20%E9%9B%86%E7%BE%A4%E8%AF%BB%E5%86%99%E5%88%86%E7%A6%BB/01.jpeg?raw=true" alt=""></figure></p>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;mysql-proxy：mysql-proxy为mysql开源项目，通过其自带的lua脚本进行sql判断，虽然是mysql官方产品，但是mysql官方并不建议将mysql-proxy用到生产环境。  </p>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;amoeba：由陈思儒开发，作者曾就职于阿里巴巴，现就职于盛大。该程序由java语言进行开发，目前只听说阿里巴巴将其用于生产环境。另外，此项目严重缺少维护和推广（作者有个官方博客，很多用户反馈的问题发现作者不理睬） </p>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;经过上述简单的比较，通过程序代码实现mysql读写分离自然是一个不错的选择。但是并不是所有的应用都适合在程序代码中实现读写分离，像大型SNS、B2C这类应用可以在代码中实现，因为这样对程序代码本身改动较小；像一些大型复杂的java应用，这种类型的应用在代码中实现对代码改动就较大了。所以，像这种应用一般就会考虑使用代理层来实现。</p>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;下面我们看一下如何搭建mysql-proxy来实现mysql读写分离 </p>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;环境拓扑如下： </p>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;关于mysql、mysql主从的搭建，在此不再演示，如下的操作均在mysql-proxy（192.168.1.200）服务器进行 </p>
<h2 id="一、安装mysql-proxy"><a href="#一、安装mysql-proxy" class="headerlink" title="一、安装mysql-proxy"></a>一、安装mysql-proxy</h2><h3 id="1、安装lua-mysql-proxy需要使用lua脚本进行数据转发"><a href="#1、安装lua-mysql-proxy需要使用lua脚本进行数据转发" class="headerlink" title="1、安装lua  (mysql-proxy需要使用lua脚本进行数据转发)"></a>1、安装lua  (mysql-proxy需要使用lua脚本进行数据转发)</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div></pre></td><td class="code"><pre><div class="line">tar zxvf lua-5.1.4.tar.gz </div><div class="line"><span class="built_in">cd</span> lua-5.1.4</div></pre></td></tr></table></figure>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;vi Makefile，修改INSTALL_TOP= /usr/local/lua </p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div></pre></td><td class="code"><pre><div class="line">make posix </div><div class="line">make install</div></pre></td></tr></table></figure>
<h3 id="2、安装libevent"><a href="#2、安装libevent" class="headerlink" title="2、安装libevent"></a>2、安装libevent</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div></pre></td><td class="code"><pre><div class="line">tar zxvf libevent-2.0.8-rc.tar.gz </div><div class="line"><span class="built_in">cd</span> libevent-2.0.8-rc </div><div class="line">./configure --prefix=/usr/<span class="built_in">local</span>/libevent </div><div class="line">make &amp;&amp; make install</div></pre></td></tr></table></figure>
<h3 id="3、安装check"><a href="#3、安装check" class="headerlink" title="3、安装check"></a>3、安装check</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div></pre></td><td class="code"><pre><div class="line">tar zxvf check-0.9.8.tar.gz </div><div class="line"><span class="built_in">cd</span> check-0.9.8 </div><div class="line"></div><div class="line">./configure &amp;&amp; make &amp;&amp; make install</div></pre></td></tr></table></figure>
<h3 id="4、安装mysql客户端"><a href="#4、安装mysql客户端" class="headerlink" title="4、安装mysql客户端"></a>4、安装mysql客户端</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div></pre></td><td class="code"><pre><div class="line">tar zxvf mysql-5.0.92.tar.gz </div><div class="line"><span class="built_in">cd</span> mysql-5.0.92 </div><div class="line">./configure </div><div class="line">--without-server &amp;&amp; make &amp;&amp; make install</div></pre></td></tr></table></figure>
<h3 id="5、设置环境变量"><a href="#5、设置环境变量" class="headerlink" title="5、设置环境变量"></a>5、设置环境变量</h3><p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;（安装mysql-proxy所需变量） </p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div></pre></td><td class="code"><pre><div class="line">vi /etc/profile </div><div class="line"></div><div class="line"><span class="built_in">export</span> </div><div class="line">LUA_CFLAGS=<span class="string">"-I/usr/local/lua/include"</span> LUA_LIBS=<span class="string">"-L/usr/local/lua/lib -llua -ldl"</span> </div><div class="line">LDFLAGS=<span class="string">"-L/usr/local/libevent/lib -lm"</span> </div><div class="line"><span class="built_in">export</span> </div><div class="line">CPPFLAGS=<span class="string">"-I/usr/local/libevent/include"</span> </div><div class="line"><span class="built_in">export</span> </div><div class="line">CFLAGS=<span class="string">"-I/usr/local/libevent/include"</span> </div><div class="line"><span class="comment"># source /etc/profile</span></div></pre></td></tr></table></figure>
<h3 id="6、安装mysql-proxy"><a href="#6、安装mysql-proxy" class="headerlink" title="6、安装mysql-proxy"></a>6、安装mysql-proxy</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div></pre></td><td class="code"><pre><div class="line">tar zxvf mysql-proxy-0.6.0.tar.gz </div><div class="line"><span class="built_in">cd</span> mysql-proxy-0.6.0 </div><div class="line"> ./configure --prefix=/usr/<span class="built_in">local</span>/mysql-proxy --with-mysql --with-lua </div><div class="line">make &amp;&amp; make install</div></pre></td></tr></table></figure>
<h3 id="7、启动mysql-proxy"><a href="#7、启动mysql-proxy" class="headerlink" title="7、启动mysql-proxy"></a>7、启动mysql-proxy</h3><p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;本次对两台数据库实现了读写分离；mysql-master为可读可写，mysql-slave为只读 </p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div></pre></td><td class="code"><pre><div class="line">/usr/<span class="built_in">local</span>/mysql-proxy/sbin/mysql-proxy </div><div class="line">--proxy-backend-addresses=192.168.1.201:3306 </div><div class="line">--proxy-read-only-backend-addresses=192.168.1.202:3306 </div><div class="line">--proxy-lua-script=/usr/<span class="built_in">local</span>/mysql-proxy/share/mysql-proxy/rw-splitting.lua </div><div class="line">&amp;</div></pre></td></tr></table></figure>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;注：如果正常情况下启动后终端不会有任何提示信息，mysql-proxy启动后会启动两个端口4040和4041，4040用于SQL转发，4041用于管理mysql-proxy。如有多个mysql-slave可以依次在后面添加 </p>
<h2 id="二、测试"><a href="#二、测试" class="headerlink" title="二、测试"></a>二、测试</h2><h3 id="1、连接测试"><a href="#1、连接测试" class="headerlink" title="1、连接测试"></a>1、连接测试</h3><p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;因为默认情况下mysql数据库不允许用户在远程连接 </p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div></pre></td><td class="code"><pre><div class="line">mysql&gt;grant </div><div class="line">all privileges on *.* to identified by <span class="string">'123456'</span>; </div><div class="line">mysql&gt;flush privileges;</div></pre></td></tr></table></figure>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;客户端连接 </p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line"><span class="comment">#mysql -uroot -p123456 -h192.168.1.200 -P4040</span></div></pre></td></tr></table></figure>
<h3 id="2、读写分离测试"><a href="#2、读写分离测试" class="headerlink" title="2、读写分离测试"></a>2、读写分离测试</h3><p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;为了测试出mysql读写分离的真实性，在测试之前，需要开启两台mysql的log功能，然后在mysql-slave服务器停止复制 </p>
<ul>
<li>在两台mysql配置文件my.cnf中加入log=query.log，然后重启</li>
<li>在mysql-slave上执行SQL语句stop slave</li>
<li>在两台mysql上执行#tail -f /usr/local/mysql/var/query.log</li>
<li>在客户端上连接mysql（三个连接以上），然后执行create、select等SQL语句，观察两台mysql的日志有何变化</li>
</ul>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;注：生产环境中除了进行程序调试外，其它不要开启mysql查询日志，因为查询日志记录了客户端的所有语句，频繁的IO操作将会导致mysql整体性能下降 </p>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;总结：在上述环境中，mysql-proxy和mysql-master、mysql-slave三台服务器均存在单点故障。如果在可用性要求较高的场合，单点隐患是绝对不允许的。为了避免mysql-proxy单点隐患有两种方法，一种方法是mysql-proxy配合keepalived做双机，另一种方法是将mysql-proxy和应用服务安装到同一台服务器上；为了避免mysql-master单点故障可以使用DRBD+heartbear做双机；避免mysql-slave单点故障增加多台mysql-slave即可，因为mysql-proxy会自动屏蔽后端发生故障的mysql-slave。</p>
<h2 id="附-mysql-proxy-LUA-读写分离脚本代码"><a href="#附-mysql-proxy-LUA-读写分离脚本代码" class="headerlink" title="附: mysql-proxy LUA 读写分离脚本代码:"></a>附: mysql-proxy LUA 读写分离脚本代码:</h2><figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div><div class="line">28</div><div class="line">29</div><div class="line">30</div><div class="line">31</div><div class="line">32</div><div class="line">33</div><div class="line">34</div><div class="line">35</div><div class="line">36</div><div class="line">37</div><div class="line">38</div><div class="line">39</div><div class="line">40</div><div class="line">41</div><div class="line">42</div><div class="line">43</div><div class="line">44</div><div class="line">45</div><div class="line">46</div><div class="line">47</div><div class="line">48</div><div class="line">49</div><div class="line">50</div><div class="line">51</div><div class="line">52</div><div class="line">53</div><div class="line">54</div><div class="line">55</div><div class="line">56</div><div class="line">57</div><div class="line">58</div><div class="line">59</div><div class="line">60</div><div class="line">61</div><div class="line">62</div><div class="line">63</div><div class="line">64</div><div class="line">65</div><div class="line">66</div><div class="line">67</div><div class="line">68</div><div class="line">69</div><div class="line">70</div><div class="line">71</div><div class="line">72</div><div class="line">73</div><div class="line">74</div><div class="line">75</div><div class="line">76</div><div class="line">77</div><div class="line">78</div><div class="line">79</div><div class="line">80</div><div class="line">81</div><div class="line">82</div><div class="line">83</div><div class="line">84</div><div class="line">85</div><div class="line">86</div><div class="line">87</div><div class="line">88</div><div class="line">89</div><div class="line">90</div><div class="line">91</div><div class="line">92</div><div class="line">93</div><div class="line">94</div><div class="line">95</div><div class="line">96</div><div class="line">97</div><div class="line">98</div><div class="line">99</div><div class="line">100</div><div class="line">101</div><div class="line">102</div><div class="line">103</div><div class="line">104</div><div class="line">105</div><div class="line">106</div><div class="line">107</div><div class="line">108</div><div class="line">109</div><div class="line">110</div><div class="line">111</div><div class="line">112</div><div class="line">113</div><div class="line">114</div><div class="line">115</div><div class="line">116</div><div class="line">117</div><div class="line">118</div><div class="line">119</div><div class="line">120</div><div class="line">121</div><div class="line">122</div><div class="line">123</div><div class="line">124</div><div class="line">125</div><div class="line">126</div><div class="line">127</div><div class="line">128</div><div class="line">129</div><div class="line">130</div><div class="line">131</div><div class="line">132</div><div class="line">133</div><div class="line">134</div><div class="line">135</div><div class="line">136</div><div class="line">137</div><div class="line">138</div><div class="line">139</div><div class="line">140</div><div class="line">141</div><div class="line">142</div><div class="line">143</div><div class="line">144</div><div class="line">145</div><div class="line">146</div><div class="line">147</div><div class="line">148</div><div class="line">149</div><div class="line">150</div><div class="line">151</div><div class="line">152</div><div class="line">153</div><div class="line">154</div><div class="line">155</div><div class="line">156</div><div class="line">157</div><div class="line">158</div><div class="line">159</div><div class="line">160</div><div class="line">161</div><div class="line">162</div><div class="line">163</div><div class="line">164</div><div class="line">165</div><div class="line">166</div><div class="line">167</div><div class="line">168</div><div class="line">169</div><div class="line">170</div><div class="line">171</div><div class="line">172</div><div class="line">173</div><div class="line">174</div><div class="line">175</div><div class="line">176</div><div class="line">177</div><div class="line">178</div><div class="line">179</div><div class="line">180</div><div class="line">181</div><div class="line">182</div><div class="line">183</div><div class="line">184</div><div class="line">185</div><div class="line">186</div><div class="line">187</div><div class="line">188</div><div class="line">189</div><div class="line">190</div><div class="line">191</div><div class="line">192</div><div class="line">193</div><div class="line">194</div><div class="line">195</div><div class="line">196</div><div class="line">197</div><div class="line">198</div><div class="line">199</div><div class="line">200</div><div class="line">201</div><div class="line">202</div><div class="line">203</div><div class="line">204</div><div class="line">205</div><div class="line">206</div><div class="line">207</div><div class="line">208</div><div class="line">209</div><div class="line">210</div><div class="line">211</div><div class="line">212</div><div class="line">213</div><div class="line">214</div><div class="line">215</div><div class="line">216</div><div class="line">217</div><div class="line">218</div><div class="line">219</div><div class="line">220</div><div class="line">221</div><div class="line">222</div><div class="line">223</div><div class="line">224</div><div class="line">225</div><div class="line">226</div><div class="line">227</div><div class="line">228</div><div class="line">229</div><div class="line">230</div><div class="line">231</div><div class="line">232</div><div class="line">233</div><div class="line">234</div><div class="line">235</div><div class="line">236</div><div class="line">237</div><div class="line">238</div><div class="line">239</div><div class="line">240</div><div class="line">241</div><div class="line">242</div><div class="line">243</div><div class="line">244</div><div class="line">245</div><div class="line">246</div><div class="line">247</div><div class="line">248</div><div class="line">249</div><div class="line">250</div><div class="line">251</div><div class="line">252</div><div class="line">253</div><div class="line">254</div><div class="line">255</div><div class="line">256</div><div class="line">257</div><div class="line">258</div><div class="line">259</div><div class="line">260</div><div class="line">261</div><div class="line">262</div><div class="line">263</div><div class="line">264</div><div class="line">265</div><div class="line">266</div><div class="line">267</div><div class="line">268</div><div class="line">269</div><div class="line">270</div><div class="line">271</div><div class="line">272</div><div class="line">273</div><div class="line">274</div><div class="line">275</div><div class="line">276</div><div class="line">277</div><div class="line">278</div><div class="line">279</div><div class="line">280</div><div class="line">281</div><div class="line">282</div><div class="line">283</div><div class="line">284</div><div class="line">285</div><div class="line">286</div><div class="line">287</div><div class="line">288</div><div class="line">289</div><div class="line">290</div><div class="line">291</div><div class="line">292</div><div class="line">293</div><div class="line">294</div><div class="line">295</div><div class="line">296</div><div class="line">297</div><div class="line">298</div><div class="line">299</div><div class="line">300</div><div class="line">301</div><div class="line">302</div><div class="line">303</div><div class="line">304</div><div class="line">305</div><div class="line">306</div><div class="line">307</div><div class="line">308</div><div class="line">309</div><div class="line">310</div><div class="line">311</div></pre></td><td class="code"><pre><div class="line">--[[</div><div class="line">--</div><div class="line">-- author : KDr2 </div><div class="line">-- version 0.01</div><div class="line">-- SYNOPSIS:</div><div class="line">---  </div><div class="line">1.维护了一个连接池</div><div class="line">---  2.读写分离，简单的将select开头的语句放到slave上执行</div><div class="line">---  </div><div class="line">3.事务支持，所有事务放到master上执行，事务中不更改连接</div><div class="line">---  4.简单日志</div><div class="line">--</div><div class="line">--]]</div><div class="line"></div><div class="line">--- config vars</div><div class="line"><span class="built_in">local</span> min_idle_connections = 4</div><div class="line"><span class="built_in">local</span> </div><div class="line">max_idle_connections = 8</div><div class="line"><span class="built_in">local</span> log_level=1</div><div class="line"><span class="built_in">local</span> encoding=<span class="string">"utf8"</span></div><div class="line">--- </div><div class="line">end of config</div><div class="line"></div><div class="line"></div><div class="line">事务标识，在事务内不归还连接</div><div class="line"></div><div class="line"><span class="built_in">local</span> </div><div class="line">transaction_flags=&#123;&#125;</div><div class="line">setmetatable(transaction_flags,&#123;__index=<span class="keyword">function</span>() </div><div class="line"><span class="built_in">return</span> 0 end&#125;)</div><div class="line"></div><div class="line">-- <span class="built_in">log</span> system</div><div class="line"><span class="built_in">log</span>=&#123;</div><div class="line">   level=&#123;debug=1,info=2,warn=3,error=4&#125;,</div><div class="line">   </div><div class="line">funcs=&#123;<span class="string">"debug"</span>,<span class="string">"info"</span>,<span class="string">"warn"</span>,<span class="string">"error"</span>&#125;,</div><div class="line">&#125;</div><div class="line"><span class="keyword">function</span> log.log(level,m)</div><div class="line">   </div><div class="line"><span class="keyword">if</span> level &gt;= log_level <span class="keyword">then</span></div><div class="line">      <span class="built_in">local</span> msg=<span class="string">"["</span> .. os.date(<span class="string">"%Y-%m-%d %X"</span>) </div><div class="line">..<span class="string">"] "</span>.. log.funcs[level] .. <span class="string">": "</span> .. tostring(m)</div><div class="line">      <span class="built_in">print</span>(msg) -- TODO  </div><div class="line">write msg into a <span class="built_in">log</span> file.</div><div class="line">   end</div><div class="line">end</div><div class="line"><span class="keyword">for</span> i,v <span class="keyword">in</span> ipairs(log.funcs) </div><div class="line"><span class="keyword">do</span></div><div class="line">   <span class="built_in">log</span>[v]=<span class="keyword">function</span>(m) log.log(log.level[v],m) end</div><div class="line">end</div><div class="line"></div><div class="line">-- connect to server</div><div class="line"><span class="keyword">function</span> connect_server() </div><div class="line">   log.info(<span class="string">" starting </span></div><div class="line"><span class="string">connect_server ... "</span>)</div><div class="line">   <span class="built_in">local</span> least_idle_conns_ndx = 0</div><div class="line">   <span class="built_in">local</span> </div><div class="line">least_idle_conns = 0</div><div class="line">   </div><div class="line">   <span class="keyword">for</span> i = 1, <span class="comment">#proxy.backends do</span></div><div class="line">      <span class="built_in">local</span> s </div><div class="line">= proxy.backends[i]</div><div class="line">      <span class="built_in">local</span> pool = s.pool </div><div class="line">      <span class="built_in">local</span> cur_idle = </div><div class="line">pool.users[<span class="string">""</span>].cur_idle_connections</div><div class="line"></div><div class="line">      log.debug(<span class="string">"["</span>.. s.address ..<span class="string">"].connected_clients = "</span> .. </div><div class="line">s.connected_clients)</div><div class="line">      log.debug(<span class="string">"["</span>.. s.address ..<span class="string">"].idling_connections </span></div><div class="line"><span class="string">= "</span> .. cur_idle)</div><div class="line">      log.debug(<span class="string">"["</span>.. s.address ..<span class="string">"].type = "</span> .. </div><div class="line">s.type)</div><div class="line">      log.debug(<span class="string">"["</span>.. s.address ..<span class="string">"].state = "</span> .. s.state)</div><div class="line"></div><div class="line">      <span class="keyword">if</span> s.state ~= proxy.BACKEND_STATE_DOWN <span class="keyword">then</span></div><div class="line">         -- try to </div><div class="line">connect to each backend once at least</div><div class="line">         <span class="keyword">if</span> cur_idle == 0 </div><div class="line"><span class="keyword">then</span></div><div class="line">            proxy.connection.backend_ndx = i</div><div class="line">            </div><div class="line">log.info(<span class="string">"server ["</span>.. proxy.backends[i].address ..<span class="string">"] open new </span></div><div class="line"><span class="string">connection"</span>)</div><div class="line">            <span class="built_in">return</span></div><div class="line">         end</div><div class="line">         -- try to open at </div><div class="line">least min_idle_connections</div><div class="line">         <span class="keyword">if</span> least_idle_conns_ndx == 0 </div><div class="line">or</div><div class="line">            ( cur_idle &lt; min_idle_connections and </div><div class="line">              </div><div class="line">cur_idle &lt; least_idle_conns ) <span class="keyword">then</span></div><div class="line">            least_idle_conns_ndx = </div><div class="line">i</div><div class="line">            least_idle_conns = cur_idle</div><div class="line">         end</div><div class="line">      end</div><div class="line">   </div><div class="line">end</div><div class="line"></div><div class="line">   <span class="keyword">if</span> least_idle_conns_ndx &gt; 0 <span class="keyword">then</span></div><div class="line">      proxy.connection.backend_ndx </div><div class="line">= least_idle_conns_ndx</div><div class="line">   end</div><div class="line">   </div><div class="line">   <span class="keyword">if</span> proxy.connection.backend_ndx </div><div class="line">&gt; 0 <span class="keyword">then</span> </div><div class="line">      <span class="built_in">local</span> s = </div><div class="line">proxy.backends[proxy.connection.backend_ndx]</div><div class="line">      <span class="built_in">local</span> pool = s.pool </div><div class="line"></div><div class="line">      <span class="built_in">local</span> cur_idle = pool.users[<span class="string">""</span>].cur_idle_connections</div><div class="line"></div><div class="line">      <span class="keyword">if</span> cur_idle &gt;= min_idle_connections <span class="keyword">then</span></div><div class="line">         -- we have 4 </div><div class="line">idling connections <span class="keyword">in</span> the pool, that<span class="string">'s good enough</span></div><div class="line"><span class="string">         log.debug("using </span></div><div class="line"><span class="string">pooled connection from: " .. proxy.connection.backend_ndx)</span></div><div class="line"><span class="string">         return </span></div><div class="line"><span class="string">proxy.PROXY_IGNORE_RESULT</span></div><div class="line"><span class="string">      end</span></div><div class="line"><span class="string">   end</span></div><div class="line"><span class="string">   -- open a new connection </span></div><div class="line"><span class="string"></span></div><div class="line"><span class="string">   log.info("opening new connection on: " .. </span></div><div class="line"><span class="string">proxy.backends[proxy.connection.backend_ndx].address)</span></div><div class="line"><span class="string">end</span></div><div class="line"><span class="string"></span></div><div class="line"><span class="string">---</span></div><div class="line"><span class="string"></span></div><div class="line"><span class="string">-- auth.packet is the packet</span></div><div class="line"><span class="string">function read_auth_result( auth )</span></div><div class="line"><span class="string">   if </span></div><div class="line"><span class="string">auth.packet:byte() == proxy.MYSQLD_PACKET_OK then</span></div><div class="line"><span class="string">      -- 连接正常</span></div><div class="line"><span class="string">      </span></div><div class="line"><span class="string">proxy.connection.backend_ndx = 0</span></div><div class="line"><span class="string">   elseif auth.packet:byte() == </span></div><div class="line"><span class="string">proxy.MYSQLD_PACKET_EOF then</span></div><div class="line"><span class="string">      -- we received either a </span></div><div class="line"><span class="string">      -- * </span></div><div class="line"><span class="string">MYSQLD_PACKET_ERR and the auth failed or</span></div><div class="line"><span class="string">      -- * MYSQLD_PACKET_EOF which </span></div><div class="line"><span class="string">means a OLD PASSWORD (4.0) was sent</span></div><div class="line"><span class="string">      log.error("(read_auth_result) ... </span></div><div class="line"><span class="string">not ok yet");</span></div><div class="line"><span class="string">   elseif auth.packet:byte() == proxy.MYSQLD_PACKET_ERR </span></div><div class="line"><span class="string">then</span></div><div class="line"><span class="string">      log.error("auth failed!")</span></div><div class="line"><span class="string">   end</span></div><div class="line"><span class="string">end</span></div><div class="line"><span class="string"></span></div><div class="line"><span class="string"></span></div><div class="line"><span class="string">--- </span></div><div class="line"><span class="string">-- read/write splitting</span></div><div class="line"><span class="string">function read_query( packet ) </span></div><div class="line"><span class="string">   </span></div><div class="line"><span class="string">log.debug("[read_query]")</span></div><div class="line"><span class="string">   log.debug("authed backend = " .. </span></div><div class="line"><span class="string">proxy.connection.backend_ndx)</span></div><div class="line"><span class="string">   log.debug("used db = " .. </span></div><div class="line"><span class="string">proxy.connection.client.default_db)</span></div><div class="line"><span class="string"></span></div><div class="line"><span class="string">   if packet:byte() == proxy.COM_QUIT then</span></div><div class="line"><span class="string">      proxy.response = </span></div><div class="line"><span class="string">&#123;</span></div><div class="line"><span class="string">         type = proxy.MYSQLD_PACKET_OK,</span></div><div class="line"><span class="string">      &#125;</span></div><div class="line"><span class="string">      return </span></div><div class="line"><span class="string">proxy.PROXY_SEND_RESULT</span></div><div class="line"><span class="string">   end</span></div><div class="line"><span class="string"></span></div><div class="line"><span class="string">   if proxy.connection.backend_ndx == 0 then</span></div><div class="line"><span class="string">      local </span></div><div class="line"><span class="string">is_read=(string.upper(packet:sub(2))):match("^SELECT")</span></div><div class="line"><span class="string">      local </span></div><div class="line"><span class="string">target_type=proxy.BACKEND_TYPE_RW</span></div><div class="line"><span class="string">      if is_read then </span></div><div class="line"><span class="string">target_type=proxy.BACKEND_TYPE_RO end</span></div><div class="line"><span class="string">      for i = 1, #proxy.backends </span></div><div class="line"><span class="string">do</span></div><div class="line"><span class="string">         local s = proxy.backends[i]</span></div><div class="line"><span class="string">         local pool = s.pool </span></div><div class="line"><span class="string"></span></div><div class="line"><span class="string">         local cur_idle = </span></div><div class="line"><span class="string">pool.users[proxy.connection.client.username].cur_idle_connections</span></div><div class="line"><span class="string">         </span></div><div class="line"><span class="string"></span></div><div class="line"><span class="string">         if cur_idle &gt; 0 and </span></div><div class="line"><span class="string">            s.state ~= </span></div><div class="line"><span class="string">proxy.BACKEND_STATE_DOWN and </span></div><div class="line"><span class="string">            s.type == target_type </span></div><div class="line"><span class="string">then</span></div><div class="line"><span class="string">            proxy.connection.backend_ndx = i</span></div><div class="line"><span class="string">            </span></div><div class="line"><span class="string">break</span></div><div class="line"><span class="string">         end</span></div><div class="line"><span class="string">      end</span></div><div class="line"><span class="string">   end</span></div><div class="line"><span class="string">   -- sync the client-side </span></div><div class="line"><span class="string">default_db with the server-side default_db</span></div><div class="line"><span class="string">   if proxy.connection.server and </span></div><div class="line"><span class="string">proxy.connection.client.default_db ~= proxy.connection.server.default_db </span></div><div class="line"><span class="string">then</span></div><div class="line"><span class="string">      local server_db=proxy.connection.server.default_db</span></div><div class="line"><span class="string">      local </span></div><div class="line"><span class="string">client_db=proxy.connection.client.default_db</span></div><div class="line"><span class="string">      local default_db= </span></div><div class="line"><span class="string">(#client_db &gt; 0) and client_db or server_db</span></div><div class="line"><span class="string">      if #default_db &gt; 0 </span></div><div class="line"><span class="string">then</span></div><div class="line"><span class="string">         proxy.queries:append(2, string.char(proxy.COM_INIT_DB) .. </span></div><div class="line"><span class="string">default_db)</span></div><div class="line"><span class="string">         proxy.queries:append(2, string.char(proxy.COM_QUERY) .. </span></div><div class="line"><span class="string">"set names '</span><span class="string">" .. encoding .."</span><span class="string">'")</span></div><div class="line"><span class="string">         log.info("change database to " .. </span></div><div class="line"><span class="string">default_db);</span></div><div class="line"><span class="string">      end</span></div><div class="line"><span class="string">   end</span></div><div class="line"><span class="string">   if proxy.connection.backend_ndx &gt; 0 </span></div><div class="line"><span class="string">then</span></div><div class="line"><span class="string">      log.debug("Query[" .. packet:sub(2) .. "] Target is [" .. </span></div><div class="line"><span class="string">proxy.backends[proxy.connection.backend_ndx].address .."]")</span></div><div class="line"><span class="string">   end</span></div><div class="line"><span class="string">   </span></div><div class="line"><span class="string">proxy.queries:append(1, packet)</span></div><div class="line"><span class="string">   return proxy.PROXY_SEND_QUERY</span></div><div class="line"><span class="string">end</span></div><div class="line"><span class="string"></span></div><div class="line"><span class="string">---</span></div><div class="line"><span class="string">-- as long as we are in a transaction keep the connection</span></div><div class="line"><span class="string">-- </span></div><div class="line"><span class="string">otherwise release it so another client can use it</span></div><div class="line"><span class="string">function read_query_result( </span></div><div class="line"><span class="string">inj ) </span></div><div class="line"><span class="string">   local res      = assert(inj.resultset)</span></div><div class="line"><span class="string">   local flags    = </span></div><div class="line"><span class="string">res.flags</span></div><div class="line"><span class="string"></span></div><div class="line"><span class="string">   if inj.id ~= 1 then</span></div><div class="line"><span class="string">      -- ignore the result of the USE </span></div><div class="line"><span class="string">&lt;default_db&gt;</span></div><div class="line"><span class="string">      return proxy.PROXY_IGNORE_RESULT</span></div><div class="line"><span class="string">   end</span></div><div class="line"><span class="string">   </span></div><div class="line"><span class="string">is_in_transaction = flags.in_trans</span></div><div class="line"><span class="string"></span></div><div class="line"><span class="string">   if flags.in_trans then</span></div><div class="line"><span class="string">      </span></div><div class="line"><span class="string">transaction_flags[proxy.connection.server.thread_id] = </span></div><div class="line"><span class="string">transaction_flags[proxy.connection.server.thread_id] + 1</span></div><div class="line"><span class="string">   elseif </span></div><div class="line"><span class="string">inj.query:sub(2):lower():match("^%s*commit%s*$") or </span></div><div class="line"><span class="string">inj.query:sub(2):lower():match("^%s*rollback%s*$") then</span></div><div class="line"><span class="string">      </span></div><div class="line"><span class="string">transaction_flags[proxy.connection.server.thread_id] = </span></div><div class="line"><span class="string">transaction_flags[proxy.connection.server.thread_id] - 1</span></div><div class="line"><span class="string">      if </span></div><div class="line"><span class="string">transaction_flags[proxy.connection.server.thread_id] &lt; 0 then </span></div><div class="line"><span class="string">transaction_flags[proxy.connection.server.thread_id] = 0 end</span></div><div class="line"><span class="string">   end</span></div><div class="line"><span class="string">   </span></div><div class="line"><span class="string"></span></div><div class="line"><span class="string">   log.debug("transaction res : " .. </span></div><div class="line"><span class="string">tostring(transaction_flags[proxy.connection.server.thread_id]));</span></div><div class="line"><span class="string">   if </span></div><div class="line"><span class="string">transaction_flags[proxy.connection.server.thread_id]==0 or </span></div><div class="line"><span class="string">transaction_flags[proxy.connection.server.thread_id] == nil then </span></div><div class="line"><span class="string">      -- </span></div><div class="line"><span class="string">isnot in a transaction, need to release the backend</span></div><div class="line"><span class="string">      </span></div><div class="line"><span class="string">proxy.connection.backend_ndx = 0</span></div><div class="line"><span class="string">   end</span></div><div class="line"><span class="string">end</span></div><div class="line"><span class="string"></span></div><div class="line"><span class="string">--- </span></div><div class="line"><span class="string">-- close the connections if we have enough connections in the </span></div><div class="line"><span class="string">pool</span></div><div class="line"><span class="string">--</span></div><div class="line"><span class="string">-- @return nil - close connection </span></div><div class="line"><span class="string">-- IGNORE_RESULT - store </span></div><div class="line"><span class="string">connection in the pool</span></div><div class="line"><span class="string">function disconnect_client()</span></div><div class="line"><span class="string">   </span></div><div class="line"><span class="string">log.debug("[disconnect_client]")</span></div><div class="line"><span class="string">   if proxy.connection.backend_ndx == 0 </span></div><div class="line"><span class="string">then</span></div><div class="line"><span class="string">      for i = 1, #proxy.backends do</span></div><div class="line"><span class="string">         local s = </span></div><div class="line"><span class="string">proxy.backends[i]</span></div><div class="line"><span class="string">         local pool = s.pool </span></div><div class="line"><span class="string">         local cur_idle = </span></div><div class="line"><span class="string">pool.users[proxy.connection.client.username].cur_idle_connections</span></div><div class="line"><span class="string">         </span></div><div class="line"><span class="string"></span></div><div class="line"><span class="string">         if s.state ~= proxy.BACKEND_STATE_DOWN and</span></div><div class="line"><span class="string">            cur_idle </span></div><div class="line"><span class="string">&gt; max_idle_connections then</span></div><div class="line"><span class="string">            -- try to disconnect a </span></div><div class="line"><span class="string">backend</span></div><div class="line"><span class="string">            proxy.connection.backend_ndx = i</span></div><div class="line"><span class="string">            </span></div><div class="line"><span class="string">log.info("[".. proxy.backends[i].address .."] closing connection, idling: " .. </span></div><div class="line"><span class="string">cur_idle)</span></div><div class="line"><span class="string">            return</span></div><div class="line"><span class="string">         end</span></div><div class="line"><span class="string">      end</span></div><div class="line"><span class="string">      return </span></div><div class="line"><span class="string">proxy.PROXY_IGNORE_RESULT</span></div><div class="line"><span class="string">   end</span></div><div class="line"><span class="string">end</span></div></pre></td></tr></table></figure>
	

	

</article>




	<article>
	
		<h1><a href="/2017/10/12/MySQL/35. 使用 Xtrabackup 在线对MySQL做主从复制/">使用 Xtrabackup 在线对MySQL做主从复制</a></h1>
	
	<div class="article__infos">
		<span class="article__date">2017-10-12</span><br />
		
		
			<span class="article__tags">
			  	<a class="article__tag-link" href="/tags/MySQL/">MySQL</a>
			</span>
		
	</div>

	

	
		<h2 id="说明"><a href="#说明" class="headerlink" title="说明"></a>说明</h2><h3 id="xtrabackup"><a href="#xtrabackup" class="headerlink" title="xtrabackup"></a>xtrabackup</h3><p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;mysqldump对于导出10G以下的数据库或几个表，还是适用的，而且更快捷。一旦数据量达到100-500G，无论是对原库的压力还是导出的性能，mysqldump就力不从心了。Percona-Xtrabackup备份工具，是实现MySQL在线热备工作的不二选择，可进行全量、增量、单表备份和还原。（但当数据量更大时，可能需要考虑分库分表，或使用 LVM 快照来加快备份速度了）</p>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;2.2版本 xtrabackup 能对InnoDB和XtraDB存储引擎的数据库非阻塞地备份，innobackupex通过perl封装了一层xtrabackup，对MyISAM的备份通过加表读锁的方式实现。2.3版本 xtrabackup 命令直接支持MyISAM引擎。<br>XtraBackup优势 ：</p>
<ol>
<li>无需停止数据库进行InnoDB热备</li>
<li>增量备份MySQL</li>
<li>流压缩到传输到其它服务器</li>
<li>能比较容易地创建主从同步</li>
<li>备份MySQL时不会增大服务器负载</li>
</ol>
<h3 id="replication"><a href="#replication" class="headerlink" title="replication"></a>replication</h3><h4 id="1-为什么要做主从复制？"><a href="#1-为什么要做主从复制？" class="headerlink" title="1. 为什么要做主从复制？"></a>1. 为什么要做主从复制？</h4><p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;我想这是要在实施以前要想清楚的问题。是为了实现读写分离，减轻主库负载或数据分析？ 为了数据安全，做备份恢复？主从切换做高可用？</p>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;大部分场景下，以上三个问号一主一从都能够解决，而且任何生产环境都建议你至少要有一个从库，假如你的读操作压力特别大，甚至要做一主多从，还可以不同的slave扮演不同的角色，例如使用不同的索引，或者不同的存储引擎，或使用一个小内存server做slave只用于备份。（当然slave太多也会对master的负载和网络带宽造成压力，此时可以考虑级联复制，即 A-&gt;B-&gt;C ）</p>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;还有需要考虑的是，一主一从，一旦做了主从切换，不通过其它HA手段干预的话，业务访问的还是原IP，而且原主库很容易就作废了。于是 主-主 复制就产生了，凭借各自不同的 server-id ，可以避免 “A的变化同步到B，B应用变化又同步到A” 这样循环复制的问题。但建议是，主主复制，其中一个主库强制设置为只读，主从切换后架构依然是可用的。</p>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;复制过程是slave主动向master拉取，而不是master去推的，所以理想情况下做搭建主从时不需要master做出任何改变甚至停服，slave失败也不影响主库。</p>
<h5 id="复制类型"><a href="#复制类型" class="headerlink" title="复制类型"></a>复制类型</h5><ul>
<li>基于语句的复制：STATEMENT，在主服务器上执行的SQL语句，在从服务器上执行同样的语句，有可能会由于SQL执行上下文环境不同而是数据不一致，例如调用NOW()函数。MySQL在5.7.7以前默认采用基于语句的复制，在 5.7.7 及以后版本默认改用 row-based。</li>
<li>基于行的复制：ROW，把改变的内容复制过去，而不是把命令在从服务器上执行一遍。从mysql5.0开始支持，能够严格保证数据完全一致，但此时用mysqlbinlog去分析日志就没啥意义。因为任何一条update语句，都会把涉及到的行数据全部set值，所以binlog文件会比较大。<br>（遇到的一个坑是，迁移时，从库改正了字段默认值定义，但数据在主库更改后，即使产生的新数据默认值是正确的，但基于行的复制依然用不正确的值字段全部更新了）</li>
<li>混合类型的复制: MIXED，默认采用基于语句的复制，一旦发现基于语句的无法精确的复制时，就会采用基于行的复制。</li>
</ul>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;mysql系统库<code>mysql</code>库里面表的日志记录格式需要说明：在通过如INSERT、UPDATE、DELETE、TRUNCATE等方式直接修改数据的语句，使用<code>binlog_format</code>指定的方式记录，但使用GRANT、ALTER、CREATE、RENAME等改动的mysql库里数据的，会强制使用<code>statement-based</code>方式记录binlog。</p>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;可以在线修改二进制日志类型，如<code>SET SESSION binlog_format=MIXED;</code>，需要SUPER权限。</p>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;复制类型还可以分为 异步复制和半同步复制。</p>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;通常没说明指的都是异步，即主库执行完Commit后，在主库写入Binlog日志后即可成功返回客户端，无需等等Binlog日志传送给从库，一旦主库宕机，有可能会丢失日志。而半同步复制，是等待其中一个从库也接收到Binlog事务并成功写入Relay Log之后，才返回Commit操作成功给客户端；如此半同步就保证了事务成功提交后至少有两份日志记录，一份在主库Binlog上，另一份在从库的Relay Log上，从而进一步保证数据完整性；半同步复制很大程度取决于主从网络RTT（往返时延），以插件 semisync_master/semisync_slave 形式存在。</p>
<h5 id="原理"><a href="#原理" class="headerlink" title="原理"></a>原理</h5><ol>
<li>master将改变记录到二进制日志(binary log)中（这些记录叫做二进制日志事件，binary log events）；</li>
<li>slave将master的binary log events拷贝到它的中继日志(relay log)；</li>
<li>slave重做中继日志中的事件，将改变反映它自己的数据。</li>
</ol>
<p><figure class="figure"><img src="https://github.com/hcldirgit/image/blob/master/%E4%BD%BF%E7%94%A8%20Xtrabackup%20%E5%9C%A8%E7%BA%BF%E5%AF%B9MySQL%E5%81%9A%E4%B8%BB%E4%BB%8E%E5%A4%8D%E5%88%B6/01.jpeg?raw=true" alt=""></figure></p>
<ul>
<li>该过程的第一部分就是master记录二进制日志。在每个事务更新数据完成之前，master在二进制日志记录这些改变。MySQL将事务串行的写入二进制日志，即使事务中的语句都是交叉执行的。在事件写入二进制日志完成后，master通知存储引擎提交事务。</li>
<li>下一步将master的binary log拷贝到它自己的中继日志。首先，slave开始一个工作线程——I/O线程。I/O线程在master上打开一个普通的连接，请求从指定日志文件的指定位置之后的日志内容，然后开始binlog dump process。Binlog dump process从master的二进制日志中读取事件，如果已经跟上master，它会睡眠并等待master产生新的事件。I/O线程将这些事件写入中继日志。</li>
<li>SQL slave thread（SQL从线程）处理该过程的最后一步。SQL线程从中继日志读取事件，并重放其中的事件而更新slave的数据，使其与master中的数据一致。只要该线程与I/O线程保持一致，中继日志通常会位于OS的缓存中，所以中继日志的开销很小。</li>
</ul>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;此外，在master中也有一个工作线程：和其它MySQL的连接一样，slave在master中打开一个连接也会使得master开始一个线程。复制过程有一个很重要的限制——复制在slave上是串行化的，也就是说master上的并行更新操作不能在slave上并行操作。</p>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;补充:</p>
<ul>
<li>mysql 5.7开始加入了多源复制，这个特性对同时有很多个mysql实例是很有用的，阿里云RDS（迁移）实现了类似的方式。</li>
<li>从MySQL 5.6.2开始，mysql binlog支持checksum校验，并且5.6.6默认启用（CRC32），这对自己模拟实现mysql复制的场景有影响。</li>
</ul>
<h5 id="下面开始配置主从："><a href="#下面开始配置主从：" class="headerlink" title="下面开始配置主从："></a>下面开始配置主从：</h5><p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;主从版本一致—&gt;主库授权复制帐号—&gt;确保开启binlog及主从server_id唯一—&gt;xtrabackup恢复到从库—&gt;记录xtrabackup_binlog_info中binlog名称及偏移量—&gt;从库change master to —&gt;slave start—&gt;检查两个yes</p>
<h4 id="2-创建复制账号"><a href="#2-创建复制账号" class="headerlink" title="2. 创建复制账号"></a>2. 创建复制账号</h4><p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;在主库上</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div></pre></td><td class="code"><pre><div class="line">mysql&gt; GRANT REPLICATION SLAVE ON *.* TO <span class="string">'slave_ali'</span>@<span class="string">'192.168.5.%'</span> IDENTIFIED BY <span class="string">'slave_ali_pass'</span>;  </div><div class="line">mysql&gt; FLUSH PRIVILEGES;</div></pre></td></tr></table></figure>
<h4 id="3-使用Percona-Xtrabackup恢复数据"><a href="#3-使用Percona-Xtrabackup恢复数据" class="headerlink" title="3. 使用Percona-Xtrabackup恢复数据"></a>3. 使用Percona-Xtrabackup恢复数据</h4><p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;这里假设比较简单的情况：全量备份，全量恢复，不涉及增量。</p>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;赋予备份用户权限：</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div></pre></td><td class="code"><pre><div class="line">mysql&gt; CREATE USER <span class="string">'bkpuser'</span>@<span class="string">'localhost'</span> IDENTIFIED BY <span class="string">'bkppass'</span>;</div><div class="line">mysql&gt; GRANT RELOAD, LOCK TABLES, REPLICATION CLIENT,PROCESS,SUPER ON *.* TO <span class="string">'bkpuser'</span>@<span class="string">'localhost'</span>;</div><div class="line">mysql&gt; FLUSH PRIVILEGES;</div></pre></td></tr></table></figure>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;完整的选项使用请执行innobackupex –-help，这里只介绍使用常用的选项进行完整备份及增量备份和还原。</p>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;这一节是把数据恢复到从库，借此记录一下xtrabackup的使用（用了云之后，备份技能都丢了~）。生产环境你应该是早就有了xtrabackup的备份，做从库时只需要把备份拷过来，解压恢复。</p>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;假设 MySQL 安装目录在<code>/opt/mysql</code>，my.cnf配置文件<code>/opt/mysql/my.cnf</code>，端口3306，数据目录<code>/opt/mysql_data</code>，sock位于<code>/opt/mysql_data/mysql.sock</code>。备份数据放在<code>/data/backup/mysql/</code>。</p>
<h5 id="全量备份"><a href="#全量备份" class="headerlink" title="全量备份"></a>全量备份</h5><figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div></pre></td><td class="code"><pre><div class="line">$ <span class="built_in">export</span> BKP_PASS=<span class="string">"bkppass"</span></div><div class="line">$ innobackupex --defaults-file=/opt/mysql/my.cnf --host=localhost --port=3306 --user=bkpuser --password=<span class="variable">$&#123;BKP_PASS&#125;</span> /data/backup/mysql</div></pre></td></tr></table></figure>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;默认会以当天 日期+时间 戳命名备份目录，如 2015-09-16_00-00-02。一般会对它进行tar压缩，由于tar只能单进程，所以往往这个压缩过程会比备份过程耗时2倍还多。拷贝到需要恢复（做从库）的目录。</p>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;<strong>如果手头有一份未压缩的全备数据，要在另一台恢复，其实还不如直接 rsync 过来，将近400G的数据压缩与解压缩过程特别漫长。</strong></p>
<h5 id="全量恢复"><a href="#全量恢复" class="headerlink" title="全量恢复"></a>全量恢复</h5><p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;在恢复的数据库服务器（从库）上：</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div></pre></td><td class="code"><pre><div class="line">恢复准备</div><div class="line">$ innobackupex --use-memory=16G --apply-log 2015-09-16_00-00-02</div><div class="line">确认数据库是关闭的，并且datadir，目录下为空</div><div class="line">$ innobackupex --defaults-file=/opt/mysql/my.cnf --use-memory=16G --copy-back 2015-09-16_00-00-02</div></pre></td></tr></table></figure>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;<strong>第一步是恢复准备，apply-log应用全备时 log sequence number 之后的数据，完了后会输出类似 InnoDB: Last MySQL binlog file position 0 262484673, file name ./mysql-bin.000135 的信息，告诉我们了后面的从库应该从哪个地方开始复制。时间不会很长，但最好用screen之类的软件放到后台执行，以免终端断开，功亏一篑。</strong></p>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;<strong>第二步使用新的my.cnf文件，将完整的mysql数据文件拷贝到datadir下。</strong></p>
<h4 id="4-做从库"><a href="#4-做从库" class="headerlink" title="4. 做从库"></a>4. 做从库</h4><p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;上面恢复过程最后一步apply-log完成之后，会得到一个lsn position 和binlog文件名：262484673、mysql-bin.000135。下面开始从库制作。</p>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;一般在<code>copy-back</code>之后需要修改数据文件目录的属性：</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">chown -R mysql.mysql /opt/mysql_data</div></pre></td></tr></table></figure>
<h5 id="my-cnf"><a href="#my-cnf" class="headerlink" title="my.cnf"></a>my.cnf</h5><p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;从库的配置文件简单一点可以从主库拷贝过来，但根据需要，要注意以下几处</p>
<ul>
<li>server-id一定不能与主库相同<br>否则，会出现如下错误：</li>
</ul>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">Slave: received end packet FROM server, apparent master shutdown</div></pre></td></tr></table></figure>
<ul>
<li>从库一般作为只读库使用，所以为安全起见，设置只读 set global read_only=1;<br>可以在从服务器的 my.cnf 里加入read-only参数来实现这一点，唯一需要注意的一点事read-only仅对没有super权限的用户有效。所以最好核对一下连接从服务器的用户，确保其没有super权限。</li>
<li>关于从库的事件<br>MYSQL Replication 可以很好的达到你的预期：从库的事件不会自己去执行，主库会把event执行的结果直接同步。在statement模式下，复制的是 event BODY 里的SQL，在row模式下是主库事件执行完成后影响的行精确复制。<br>从库 event_scheduler 参数是被忽略的，并且每个event 状态会是 SLAVESIDE_DISABLED ，但CREATE/ALTER EVENT等操作语句是会复制。主从切换后，从库事件状态会变成ENABLE。</li>
<li>参数调整<br>从库是不允许写入的，否则数据就不一致了。从库实例的配置可以不要主库那么高，比如原16G的buffer pool，根据用途，从库可以设到4-8G（当时前提是将来你也不打算把它切换为主库用）。<br>相应的，read_buffer_size，sort_buffer_size, query_cache_size 这些读相关参数可以略微增大。当然我一般都懒得去改。</li>
<li>skip-slave-start<br>主从创建完成后，默认情况下次启动从库，会自动启动复制进程，一般这也正是我们需要的，但在维护阶段时你可能不想从库启动后立即开始复制，<code>--skip-slave-start</code>选项可以帮到你。</li>
<li>log-slave-updates<br>正常情况从库是不需要写回放日志产生的binlog，无形中增加服务器压力。但如果你想要实现级联复制即 <code>A -&gt; B -&gt; C</code> ，B同时是A的从库，也是C的主库，就需要开启 log-bin 和 log-slave-updates 。</li>
</ul>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;另外，建议显示设置 <code>log-bin=mysql-bin</code> 确保主从正常切换。 show variables like ‘log%’ 查看当前值。</p>
<ul>
<li>关于过滤表见mysql-replica-filter</li>
<li>sync_binlog<br>For the greatest possible durability and consistency in a replication setup using InnoDB with transactions, you should use innodb_flush_log_at_trx_commit=1 and sync_binlog=1 in the master my.cnf file.<br>上面的话同时也意味着性能最低。可以在这埋点，假如出现慢的情况，把两参数调成2。</li>
</ul>
<h5 id="160-160-160-160-160-160-160-160-启动从库"><a href="#160-160-160-160-160-160-160-160-启动从库" class="headerlink" title="&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;启动从库"></a>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;启动从库</h5><p>启动数据库，注意看日志</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">/opt/mysql/bin/mysqld_safe --defaults-file=/opt/mysql/my.cnf &amp;</div></pre></td></tr></table></figure>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;提示：如果你不确定这个库是谁的从库，保守起见加上–skip-slave-start启动，兴许能防止数据不一致。</p>
<h5 id="change-master"><a href="#change-master" class="headerlink" title="change master"></a>change master</h5><p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;在从库上</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div></pre></td><td class="code"><pre><div class="line">$ mysql -uslave_ali -p<span class="string">'slave_ali_pass'</span> -S /opt/mysql_data/mysql.sock</div><div class="line"></div><div class="line">mysql&gt; change master to master_host=MASTER_HOST, master_port=3306, </div><div class="line">       master_user=<span class="string">'slave_ali'</span>,master_password=<span class="string">'slave_ali_pass'</span>,</div><div class="line">       master_log_file=<span class="string">'mysql-bin.000135'</span>, master_log_pos=262484673;</div></pre></td></tr></table></figure>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;上面的 master_log_file 和 master_log_pos 即是输出的值，也可以在新的数据目录下<code>xtrabackup_binlog_info</code>找到信息。</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div></pre></td><td class="code"><pre><div class="line">mysql&gt; show slave status\G</div><div class="line">mysql&gt; start slave;</div><div class="line">mysql&gt; show slave status\G</div></pre></td></tr></table></figure>
<h5 id="验证同步延迟"><a href="#验证同步延迟" class="headerlink" title="验证同步延迟"></a>验证同步延迟</h5><p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;从库执行 show slave status\G</p>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;节选：</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div></pre></td><td class="code"><pre><div class="line">Slave_IO_State: Waiting <span class="keyword">for</span> master to send event</div><div class="line"> Master_Log_File: mysql-bin.000004</div><div class="line"> Read_Master_Log_Pos: 931</div><div class="line"> Relay_Log_File: slave1-relay-bin.000056</div><div class="line"> Relay_Log_Pos: 950</div><div class="line">Relay_Master_Log_File: mysql-bin.000004</div><div class="line"> Slave_IO_Running: Yes</div><div class="line"> Slave_SQL_Running: Yes</div><div class="line"> Exec_Master_Log_Pos: 931</div><div class="line"> Relay_Log_Space: 408</div><div class="line">Seconds_Behind_Master: 0</div></pre></td></tr></table></figure>
<ul>
<li><code>Master_Log_File</code>： I/O线程当前正在读取的主服务器二进制日志文件的名称</li>
<li><code>Read_Master_Log_Pos</code>：本机I/O线程读取主服务器二进制日志位置<br>上面2各值，与在主库执行show master status;看到的值如果基本接近，说明从库IO线程已经赶上了主库的binlog。</li>
<li><code>Relay_Master_Log_File</code>: 由SQL线程执行的包含多数近期事件的主服务器二进制日志文件的名称</li>
<li><code>Exec_Master_Log_Pos</code>: SQL线程执行来自master的二进制日志最后一个事件位置<br>与上面的<code>Relay_Master_Log_File</code>一起，同<code>Master_Log_File</code>、<code>Read_Master_Log_Pos</code>比较，能看到SQL线程是否已经赶上从库本地的IO线程。</li>
<li><code>Slave_IO_Running</code>：I/O线程是否启动并成功连接到主服务器上<br>一般和下面的<code>Slave_IO_Running</code>和<code>Seconds_Behind_Master</code>一起监控主从健康状态</li>
<li><code>Slave_SQL_Running</code>：SQL线程是否启动</li>
<li><code>Seconds_Behind_Master</code>: 从属服务器“落后”多少秒</li>
</ul>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;官网的解释是：The number of seconds that the slave SQL thread is behind processing the master binary log。但是当 SBM 为 0 时也不代表一定没有延迟，因为可能因为网络慢的缘故，从库的IO线程传输binlog太慢，它的SQL线程应用日志很容易就赶上relay log，但实际主库产生的binlog比传输的快，就会造成为0的假象。</p>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;有时你反复status会发现 Seconds_Behind_Master 的值在0与一个很大的数之间波动，有可能是主库上执行了一个非常大的event，没执行完毕的时候从库SBM显示为0，event执行完成并传输完binlog后，就会显示SBM非常巨大。（我在从机房迁移mysql到阿里云上部分库老出现这种情况，应该跟网络和大event都有关系）。</p>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;另外，relay log 中event记录的时间戳是主库上的时间戳，而SQL thread的时间戳是从库上的，如果主库和从库的时间偏差较大，那么这个SBM的意义就基本不存在了。</p>
<h3 id="参考"><a href="#参考" class="headerlink" title="参考"></a>参考</h3><ul>
<li><a href="http://blog.csdn.net/hguisu/article/details/7325124" target="_blank" rel="external">高性能Mysql主从架构的复制原理及配置详解</a></li>
<li><a href="https://www.percona.com/blog/2013/01/09/how-does-mysql-replication-really-work/" target="_blank" rel="external">How does MySQL Replication really work?</a></li>
<li><a href="https://segmentfault.com/a/1190000003063874" target="_blank" rel="external">XtraBackup不停机不锁表搭建MySQL主从同步实践</a></li>
<li><a href="http://www.simlinux.com/archives/236.html" target="_blank" rel="external">MySQL复制原理与配置</a></li>
<li><a href="https://dev.mysql.com/doc/refman/5.6/en/replication-administration-status.html" target="_blank" rel="external">许多模糊的内容还是看官网的</a></li>
</ul>

	

	

</article>





	<span class="different-posts">📖 <a href="/page/28">more posts</a> 📖</span>



	</main>

	<footer class="footer">
	<div class="footer-content">
		
	      <div class="footer__element">
	<p>Hi there, <br />welcome to my Blog glad you found it. Have a look around, will you?</p>
</div>

	    
	      <div class="footer__element">
	<h5>Check out</h5>
	<ul class="footer-links">
		<li class="footer-links__link"><a href="/archives">Archive</a></li>
		
		  <li class="footer-links__link"><a href="/atom.xml">RSS</a></li>
	    
		<li class="footer-links__link"><a href="/about">about page</a></li>
		<li class="footer-links__link"><a href="/tags">Tags</a></li>
		<li class="footer-links__link"><a href="/categories">Categories</a></li>
	</ul>
</div>

	    

		<div class="footer-credit">
			<span>© 2017 失落的乐章 | Powered by <a href="https://hexo.io/">Hexo</a> | Theme <a href="https://github.com/HoverBaum/meilidu-hexo">MeiliDu</a></span>
		</div>

	</div>


</footer>



</body>

</html>
